Merge branch 'main' into gh-pages

This commit is contained in:
ParkerTenBroeck 2026-04-19 17:30:07 -04:00
commit d644ce8528
10 changed files with 160 additions and 106 deletions

View file

@ -229,7 +229,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if let Some(previous) = self if let Some(previous) = self
@ -258,7 +258,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
@ -292,7 +292,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if self.states.contains_key(&State(ident)) { if self.states.contains_key(&State(ident)) {
@ -366,7 +366,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> {
}; };
for item in list { for item in list {
let Some(next_state) = item.expect_ident(self.ctx) else { let Some(next_state) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
let next_state = Spanned(next_state, item.1); let next_state = Spanned(next_state, item.1);
@ -413,11 +413,11 @@ impl<'a> Spanned<&ast::Tuple<'a>> {
ctx: &mut Context<'a>, ctx: &mut Context<'a>,
) -> Option<(Spanned<&'a str>, Spanned<ast::Symbol<'a>>)> { ) -> Option<(Spanned<&'a str>, Spanned<ast::Symbol<'a>>)> {
match &self.0.0[..] { match &self.0.0[..] {
[ [state, letter]
Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), if let Some(state) = state.string_weak()
Spanned(ast::Item::Symbol(letter), letter_span), && let Some(letter) = letter.sym_weak() =>
] => { {
return Some((Spanned(state, *state_span), Spanned(*letter, *letter_span))); return Some((state, letter));
} }
_ => { _ => {
_ = ctx.emit_error( _ = ctx.emit_error(

View file

@ -317,7 +317,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
.emit_error("accept by already set", top_level) .emit_error("accept by already set", top_level)
.emit_info("previously defined here", previous); .emit_info("previously defined here", previous);
} }
let Some(by) = item.expect_ident(self.ctx) else { let Some(by) = item.expect_ident_weak(self.ctx) else {
return; return;
}; };
@ -343,7 +343,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if let Some(previous) = self if let Some(previous) = self
@ -372,7 +372,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if let Some(previous) = self if let Some(previous) = self
@ -401,7 +401,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
@ -435,7 +435,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if self.states.contains_key(&State(ident)) { if self.states.contains_key(&State(ident)) {
@ -562,7 +562,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
if matches!(symbol.0, ast::Item::Symbol(Sym::Epsilon(_))) { if matches!(symbol.0, ast::Item::Symbol(Sym::Epsilon(_))) {
return None; return None;
} }
let ident = symbol.expect_ident(self.ctx)?; let ident = symbol.expect_ident_weak(self.ctx)?;
if !self.symbols.contains_key(&Symbol(ident)) { if !self.symbols.contains_key(&Symbol(ident)) {
self.ctx self.ctx
@ -611,16 +611,12 @@ impl<'a, 'b> Spanned<&'b ast::Tuple<'a>> {
ctx: &mut Context<'a>, ctx: &mut Context<'a>,
) -> Option<(Spanned<&'a str>, Spanned<ast::Symbol<'a>>, Spanned<&'a str>)> { ) -> Option<(Spanned<&'a str>, Spanned<ast::Symbol<'a>>, Spanned<&'a str>)> {
match &self.0.0[..] { match &self.0.0[..] {
[ [state, letter, symbol]
Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), if let Some(state) = state.string_weak()
Spanned(ast::Item::Symbol(letter), letter_span), && let Some(letter) = letter.sym_weak()
Spanned(ast::Item::Symbol(ast::Symbol::Ident(symbol)), symbol_span), && let Some(symbol) = symbol.string_weak() =>
] => { {
return Some(( return Some((state, letter, symbol));
Spanned(state, *state_span),
Spanned(*letter, *letter_span),
Spanned(symbol, *symbol_span),
));
} }
_ => { _ => {
_ = ctx.emit_error( _ = ctx.emit_error(
@ -636,11 +632,8 @@ impl<'a, 'b> Spanned<&'b ast::Tuple<'a>> {
ctx: &mut Context<'a>, ctx: &mut Context<'a>,
) -> Option<(Spanned<&'a str>, &'b [Spanned<ast::Item<'a>>])> { ) -> Option<(Spanned<&'a str>, &'b [Spanned<ast::Item<'a>>])> {
match &self.0.0[..] { match &self.0.0[..] {
[ [state, list] if let Some(state) = state.string_weak() => {
Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), return Some((state, list.list_weak()));
list,
] => {
return Some((Spanned(state, *state_span), list.list_weak()));
} }
_ => _ = ctx.emit_error("expected PDA transition (state, symbol|[symbol])", self.1), _ => _ = ctx.emit_error("expected PDA transition (state, symbol|[symbol])", self.1),
} }

View file

@ -253,7 +253,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if let Some(previous) = self if let Some(previous) = self
@ -282,7 +282,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if let Some(previous) = self if let Some(previous) = self
@ -311,7 +311,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> {
return; return;
}; };
for item in list { for item in list {
let Some(ident) = item.expect_ident(self.ctx) else { let Some(ident) = item.expect_ident_weak(self.ctx) else {
continue; continue;
}; };
if self.states.contains_key(&State(ident)) { if self.states.contains_key(&State(ident)) {
@ -413,6 +413,13 @@ impl<'a, 'b> TmCompiler<'a, 'b> {
.emit_error("transition state not defined as state", to_state.1); .emit_error("transition state not defined as state", to_state.1);
continue; continue;
}; };
if !self.symbols.contains_key(&Symbol(to_tape.0)) {
self.ctx.emit_error(
"transition tape symbol not defined as tape symbol",
to_tape.1,
);
return;
};
let entry: &mut _ = self let entry: &mut _ = self
.transitions .transitions
@ -452,11 +459,11 @@ impl<'a> Spanned<&ast::Tuple<'a>> {
ctx: &mut Context<'a>, ctx: &mut Context<'a>,
) -> Option<(Spanned<&'a str>, Spanned<&'a str>)> { ) -> Option<(Spanned<&'a str>, Spanned<&'a str>)> {
match &self.0.0[..] { match &self.0.0[..] {
[ [state, tape]
Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), if let Some(state) = state.string_weak()
Spanned(ast::Item::Symbol(ast::Symbol::Ident(tape)), tape_span), && let Some(tape) = tape.string_weak() =>
] => { {
return Some((Spanned(state, *state_span), Spanned(*tape, *tape_span))); return Some((state, tape));
} }
_ => _ = ctx.emit_error("expected TM transition function (state, symbol)", self.1), _ => _ = ctx.emit_error("expected TM transition function (state, symbol)", self.1),
} }
@ -468,28 +475,25 @@ impl<'a> Spanned<&ast::Tuple<'a>> {
ctx: &mut Context<'a>, ctx: &mut Context<'a>,
) -> Option<(Spanned<&'a str>, Spanned<&'a str>, Spanned<Direction>)> { ) -> Option<(Spanned<&'a str>, Spanned<&'a str>, Spanned<Direction>)> {
match &self.0.0[..] { match &self.0.0[..] {
[ [state, tape, direction]
Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), if let Some(state) = state.string_weak()
Spanned(ast::Item::Symbol(ast::Symbol::Ident(tape)), tape_span), && let Some(tape) = tape.string_weak()
Spanned(ast::Item::Symbol(direction), direction_span), && let Some(direction) = direction.sym_weak() =>
] => { {
let direction = match direction { let direction_span = direction.1;
let direction = match direction.0 {
ast::Symbol::Ident("left" | "L" | "<") => Direction::Left, ast::Symbol::Ident("left" | "L" | "<") => Direction::Left,
ast::Symbol::Ident("right" | "R" | ">") => Direction::Right, ast::Symbol::Ident("right" | "R" | ">") => Direction::Right,
ast::Symbol::Epsilon(_) | ast::Symbol::Ident("~") => Direction::None, ast::Symbol::Epsilon(_) | ast::Symbol::Ident("~") => Direction::None,
ast::Symbol::Ident(ident) => { ast::Symbol::Ident(ident) => {
ctx.emit_error( ctx.emit_error(
format!("invalid direction specified '{ident}'"), format!("invalid direction specified '{ident}'"),
*direction_span, direction.1,
); );
Direction::None Direction::None
} }
}; };
return Some(( return Some((state, tape, Spanned(direction, direction_span)));
Spanned(state, *state_span),
Spanned(*tape, *tape_span),
Spanned(direction, *direction_span),
));
} }
_ => { _ => {
_ = ctx.emit_error( _ = ctx.emit_error(

View file

@ -23,7 +23,7 @@ pub enum Symbol<'a> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Item<'a> { pub enum Item<'a> {
Symbol(Symbol<'a>), Symbol(Symbol<'a>),
String(Cow<'a, str>), String(&'a str),
Tuple(Tuple<'a>), Tuple(Tuple<'a>),
List(List<'a>), List(List<'a>),
} }
@ -50,7 +50,7 @@ pub struct List<'a>(pub Vec<Spanned<Item<'a>>>, pub ListKind);
pub enum ProductionUnit<'a> { pub enum ProductionUnit<'a> {
Epsilon(&'a str), Epsilon(&'a str),
Ident(&'a str), Ident(&'a str),
String(Cow<'a, str>), String(&'a str),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -73,7 +73,7 @@ pub enum TopLevel<'a> {
use crate::loader::{Context, log::LogSink}; use crate::loader::{Context, log::LogSink};
impl<'a> Spanned<Item<'a>> { impl<'a> Spanned<Item<'a>> {
pub fn expect_symbol(&self, ctx: &mut Context<'a>) -> Option<Symbol<'a>> { pub fn expect_symbol_weak(&self, ctx: &mut Context<'a>) -> Option<Symbol<'a>> {
match &self.0 { match &self.0 {
Item::Symbol(sym) => return Some(*sym), Item::Symbol(sym) => return Some(*sym),
Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1), Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1),
@ -83,15 +83,15 @@ impl<'a> Spanned<Item<'a>> {
None None
} }
pub fn expect_ident(&self, ctx: &mut Context<'a>) -> Option<&'a str> { pub fn expect_ident_weak(&self, ctx: &mut Context<'a>) -> Option<&'a str> {
match &self.0 { match &self.0 {
Item::Symbol(Symbol::Ident(ident)) => return Some(ident), Item::Symbol(Symbol::Ident(ident)) => return Some(ident),
Item::String(string) => _ = return Some(*string),
Item::Symbol(Symbol::Epsilon(_)) => { Item::Symbol(Symbol::Epsilon(_)) => {
_ = ctx.emit_error("expected ident found epsilon", self.1) _ = ctx.emit_error("expected ident/string found epsilon", self.1)
} }
Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1), Item::Tuple(_) => _ = ctx.emit_error("expected ident/string found tuple", self.1),
Item::List(_) => _ = ctx.emit_error("expected ident found list", self.1), Item::List(_) => _ = ctx.emit_error("expected ident/string found list", self.1),
Item::String(_) => _ = ctx.emit_error("expected ident found string", self.1),
} }
None None
} }
@ -140,6 +140,25 @@ impl<'a> Spanned<Item<'a>> {
} }
} }
pub fn string_weak(&self) -> Option<Spanned<&'a str>> {
match &self.0 {
Item::Symbol(Symbol::Ident(ident)) => Some(Spanned(ident, self.1)),
Item::Symbol(_) => None,
Item::String(ident) => Some(Spanned(ident, self.1)),
Item::Tuple(_) => None,
Item::List(_) => None,
}
}
pub fn sym_weak(&self) -> Option<Spanned<Symbol<'a>>> {
match &self.0 {
Item::Symbol(symbol) => Some(Spanned(*symbol, self.1)),
Item::String(ident) => Some(Spanned(Symbol::Ident(ident), self.1)),
Item::Tuple(_) => None,
Item::List(_) => None,
}
}
pub fn expect_tuple(&self, ctx: &mut Context<'a>) -> Option<Spanned<&Tuple<'a>>> { pub fn expect_tuple(&self, ctx: &mut Context<'a>) -> Option<Spanned<&Tuple<'a>>> {
match &self.0 { match &self.0 {
Item::Symbol(Symbol::Ident(_)) => { Item::Symbol(Symbol::Ident(_)) => {

View file

@ -174,7 +174,7 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
match self.consume() { match self.consume() {
Some('"') => { Some('"') => {
break Ok(Token::String( break Ok(Token::String(
&self.input[start + 1..self.position], &self.input[start + 1..self.position-1],
StringKind::Regular, StringKind::Regular,
escaped, escaped,
)); ));

View file

@ -231,11 +231,11 @@ impl<'a> Display for LogEntryDisplay<'a> {
} }
for grapheme in line.graphemes(true) { for grapheme in line.graphemes(true) {
if (span.0..span.1).contains(&index) { if (span.0..span.1).contains(&index) {
for _ in 0..width(grapheme){ for _ in 0..width(grapheme) {
write!(f, "~")?; write!(f, "~")?;
} }
} else { } else {
for _ in 0..width(grapheme){ for _ in 0..width(grapheme) {
write!(f, " ")?; write!(f, " ")?;
} }
} }

View file

@ -152,7 +152,7 @@ pub fn parse_universal<'a>(ctx: &mut Context<'a>) -> Option<Machine<'a>> {
fn parse_type<'a>(item: Option<S<TopLevel<'a>>>, ctx: &mut Context<'a>) -> Option<Type> { fn parse_type<'a>(item: Option<S<TopLevel<'a>>>, ctx: &mut Context<'a>) -> Option<Type> {
let (str, span) = match item { let (str, span) = match item {
Some(S(TopLevel::Item(S("type", _), item @ S(_, span)), _)) => { Some(S(TopLevel::Item(S("type", _), item @ S(_, span)), _)) => {
(item.expect_ident(ctx)?, span) (item.expect_ident_weak(ctx)?, span)
} }
Some(S(_, span)) => { Some(S(_, span)) => {
ctx.emit_error("expected type=<type> as first item", span) ctx.emit_error("expected type=<type> as first item", span)

View file

@ -141,7 +141,7 @@ impl<'a, 'b> Parser<'a, 'b> {
S(Tuple(items), start.join(end)) S(Tuple(items), start.join(end))
} }
fn parse_as_string(&mut self, tok: S<T<'a>>) -> S<Cow<'a, str>> { fn parse_as_string(&mut self, tok: S<T<'a>>) -> S<&'a str> {
let (r, k, e, s) = match tok { let (r, k, e, s) = match tok {
S(T::String(r, k, e), s) => (r, k, e, s), S(T::String(r, k, e), s) => (r, k, e, s),
S(t, s) => { S(t, s) => {
@ -160,7 +160,7 @@ impl<'a, 'b> Parser<'a, 'b> {
S(r.into(), s) S(r.into(), s)
} }
fn parse_string(&mut self) -> S<Cow<'a, str>> { fn parse_string(&mut self) -> S<&'a str> {
let tok = self.next_token(); let tok = self.next_token();
self.parse_as_string(tok) self.parse_as_string(tok)
} }

View file

@ -104,7 +104,7 @@ d(qc, c) = qc
new Example( new Example(
"Tutorial", "Tutorial",
"DPDA Final State", "DPDA Final State",
`// Accept strings over a,b of the form a^nb^k n != k n,k > 0 `// Accept strings over a,b of the form a^nb^k where n != k and n,k > 0
type = DPDA type = DPDA
Q = {q0, qas, qeq, qmb, qlb} // states Q = {q0, qas, qeq, qmb, qlb} // states
@ -122,7 +122,7 @@ d(qas, b, z0) = (qeq, z0)
d(qas, a, A) = (qas, [A A]) d(qas, a, A) = (qas, [A A])
d(qas, b, A) = (qlb, ~) d(qas, b, A) = (qlb, ~)
d(qlb, b, A) = (qeq, ~) d(qlb, b, A) = (qlb, ~)
d(qlb, b, z0) = (qeq, z0) d(qlb, b, z0) = (qeq, z0)
d(qeq, b, z0) = (qmb, z0) d(qeq, b, z0) = (qmb, z0)
@ -369,7 +369,7 @@ d(q1, b, B) = { (q1, epsilon) }`,
), ),
new Example("TM", "a^nb^n", new Example("TM", "a^nb^n",
`// accepts all strings on {a,b}+ of the form anbn `// accepts all strings on {a,b}+ of the form a^n^bn
type = TM type = TM
Q = { q0, q1, q2, q3, q4 } // set of internal states Q = { q0, q1, q2, q3, q4 } // set of internal states
@ -378,18 +378,19 @@ T = { a, b, X, Y, B } // tape alphabet
B = B // the blank symbol (tape initializer symbol) B = B // the blank symbol (tape initializer symbol)
q0 = q0 // initial state q0 = q0 // initial state
d(q0,a)=(q1,x,R) d(q0,a)=(q1,X,R)
d(q1,a)=(q1,a,R) d(q1,a)=(q1,a,R)
d(q1,Y)=(q1,y,R) d(q1,Y)=(q1,Y,R)
d(q1,b)=(q2,y,L) d(q1,b)=(q2,Y,L)
d(q2,Y)=(q2,y,L) d(q2,Y)=(q2,Y,L)
d(q2,a)=(q2,a,L) d(q2,a)=(q2,a,L)
d(q2,X)=(q0,x,R) d(q2,X)=(q0,X,R)
d(q0,Y)=(q3,y,R) d(q0,Y)=(q3,Y,R)
d(q3,Y)=(q3,y,R) d(q3,Y)=(q3,Y,R)
d(q3,B)=(q4,B,R) d(q3,B)=(q4,B,R)
`), `),
// new Example("CFG", "definition", // new Example("CFG", "definition",

View file

@ -1,7 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use automata::{ use automata::{
automatan::{fa::Fa, pda::Pda, tm::Tm}, delta_lower, epsilon, gamma_upper, loader::{self, Context, Machine, Span, Spanned, lexer::Lexer}, sigma_upper automatan::{fa::Fa, pda::Pda, tm::Tm},
delta_lower, epsilon, gamma_upper,
loader::{self, Context, Machine, Span, Spanned, lexer::Lexer},
sigma_upper,
}; };
use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::prelude::wasm_bindgen;
@ -148,65 +151,99 @@ pub struct CompileResult {
pub machine: Option<String>, pub machine: Option<String>,
} }
trait FixupSpan{ trait FixupSpan {
fn fixup(&mut self, func: impl FnMut(Span) -> Span); fn fixup(&mut self, func: impl FnMut(Span) -> Span);
} }
impl<'a> FixupSpan for Machine<'a>{ impl<'a> FixupSpan for Machine<'a> {
fn fixup(&mut self, func: impl FnMut(Span) -> Span) { fn fixup(&mut self, func: impl FnMut(Span) -> Span) {
match self{ match self {
Machine::Fa(fa) => fa.fixup(func), Machine::Fa(fa) => fa.fixup(func),
Machine::Pda(pda) => pda.fixup(func), Machine::Pda(pda) => pda.fixup(func),
Machine::Tm(tm) => tm.fixup(func), Machine::Tm(tm) => tm.fixup(func),
} }
} }
} }
impl<'a> FixupSpan for Fa<'a>{ impl<'a> FixupSpan for Fa<'a> {
fn fixup(&mut self, mut func: impl FnMut(Span) -> Span) { fn fixup(&mut self, mut func: impl FnMut(Span) -> Span) {
self.alphabet.values_mut().for_each(|v| v.definition = func(v.definition)); self.alphabet
self.states.values_mut().for_each(|v| v.definition = func(v.definition)); .values_mut()
self.final_states.values_mut().for_each(|v| v.definition = func(v.definition)); .for_each(|v| v.definition = func(v.definition));
self.transitions.values_mut().flat_map(|v|v.iter_mut()).for_each(|e|{ self.states
.values_mut()
.for_each(|v| v.definition = func(v.definition));
self.final_states
.values_mut()
.for_each(|v| v.definition = func(v.definition));
self.transitions
.values_mut()
.flat_map(|v| v.iter_mut())
.for_each(|e| {
e.transition = func(e.transition); e.transition = func(e.transition);
e.function = func(e.function); e.function = func(e.function);
}); });
} }
} }
impl<'a> FixupSpan for Pda<'a>{ impl<'a> FixupSpan for Pda<'a> {
fn fixup(&mut self, mut func: impl FnMut(Span) -> Span) { fn fixup(&mut self, mut func: impl FnMut(Span) -> Span) {
self.alphabet.values_mut().for_each(|v| v.definition = func(v.definition)); self.alphabet
self.states.values_mut().for_each(|v| v.definition = func(v.definition)); .values_mut()
self.symbols.values_mut().for_each(|v| v.definition = func(v.definition)); .for_each(|v| v.definition = func(v.definition));
self.final_states.as_mut().unwrap_or(&mut HashMap::new()).values_mut().for_each(|v| v.definition = func(v.definition)); self.states
self.transitions.values_mut().flat_map(|v|v.iter_mut()).for_each(|e|{ .values_mut()
.for_each(|v| v.definition = func(v.definition));
self.symbols
.values_mut()
.for_each(|v| v.definition = func(v.definition));
self.final_states
.as_mut()
.unwrap_or(&mut HashMap::new())
.values_mut()
.for_each(|v| v.definition = func(v.definition));
self.transitions
.values_mut()
.flat_map(|v| v.iter_mut())
.for_each(|e| {
e.transition = func(e.transition); e.transition = func(e.transition);
e.function = func(e.function); e.function = func(e.function);
}); });
} }
} }
impl<'a> FixupSpan for Tm<'a>{ impl<'a> FixupSpan for Tm<'a> {
fn fixup(&mut self, mut func: impl FnMut(Span) -> Span) { fn fixup(&mut self, mut func: impl FnMut(Span) -> Span) {
self.states.values_mut().for_each(|v| v.definition = func(v.definition)); self.states
self.symbols.values_mut().for_each(|v| v.definition = func(v.definition)); .values_mut()
self.final_states.values_mut().for_each(|v| v.definition = func(v.definition)); .for_each(|v| v.definition = func(v.definition));
self.transitions.values_mut().flat_map(|v|v.iter_mut()).for_each(|e|{ self.symbols
.values_mut()
.for_each(|v| v.definition = func(v.definition));
self.final_states
.values_mut()
.for_each(|v| v.definition = func(v.definition));
self.transitions
.values_mut()
.flat_map(|v| v.iter_mut())
.for_each(|e| {
e.transition = func(e.transition); e.transition = func(e.transition);
e.function = func(e.function); e.function = func(e.function);
}); });
} }
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn compile(input: &str) -> CompileResult { pub fn compile(input: &str) -> CompileResult {
let mut ctx = Context::new(input); let mut ctx = Context::new(input);
let result = automata::loader::parse_universal(&mut ctx); let result = automata::loader::parse_universal(&mut ctx);
let machine = result.map(|mut result| { let machine = result.map(|mut result| {
result.fixup(|span|Span(input[..span.0].chars().map(char::len_utf16).sum(), input[..span.1].chars().map(char::len_utf16).sum())); result.fixup(|span| {
Span(
input[..span.0].chars().map(char::len_utf16).sum(),
input[..span.1].chars().map(char::len_utf16).sum(),
)
});
serde_json::to_string(&result).unwrap() serde_json::to_string(&result).unwrap()
}); });