diff --git a/automata/src/automatan/fa.rs b/automata/src/automatan/fa.rs index 20e5117..e46c7c0 100644 --- a/automata/src/automatan/fa.rs +++ b/automata/src/automatan/fa.rs @@ -229,7 +229,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if let Some(previous) = self @@ -258,7 +258,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; @@ -292,7 +292,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if self.states.contains_key(&State(ident)) { @@ -366,7 +366,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> { }; 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; }; let next_state = Spanned(next_state, item.1); @@ -413,11 +413,11 @@ impl<'a> Spanned<&ast::Tuple<'a>> { ctx: &mut Context<'a>, ) -> Option<(Spanned<&'a str>, Spanned>)> { match &self.0.0[..] { - [ - Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), - Spanned(ast::Item::Symbol(letter), letter_span), - ] => { - return Some((Spanned(state, *state_span), Spanned(*letter, *letter_span))); + [state, letter] + if let Some(state) = state.string_weak() + && let Some(letter) = letter.sym_weak() => + { + return Some((state, letter)); } _ => { _ = ctx.emit_error( diff --git a/automata/src/automatan/pda.rs b/automata/src/automatan/pda.rs index 528fd21..e7d1c0d 100644 --- a/automata/src/automatan/pda.rs +++ b/automata/src/automatan/pda.rs @@ -317,7 +317,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> { .emit_error("accept by already set", top_level) .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; }; @@ -343,7 +343,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if let Some(previous) = self @@ -372,7 +372,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if let Some(previous) = self @@ -401,7 +401,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; @@ -435,7 +435,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; 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(_))) { return None; } - let ident = symbol.expect_ident(self.ctx)?; + let ident = symbol.expect_ident_weak(self.ctx)?; if !self.symbols.contains_key(&Symbol(ident)) { self.ctx @@ -611,16 +611,12 @@ impl<'a, 'b> Spanned<&'b ast::Tuple<'a>> { ctx: &mut Context<'a>, ) -> Option<(Spanned<&'a str>, Spanned>, Spanned<&'a str>)> { match &self.0.0[..] { - [ - Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), - Spanned(ast::Item::Symbol(letter), letter_span), - Spanned(ast::Item::Symbol(ast::Symbol::Ident(symbol)), symbol_span), - ] => { - return Some(( - Spanned(state, *state_span), - Spanned(*letter, *letter_span), - Spanned(symbol, *symbol_span), - )); + [state, letter, symbol] + if let Some(state) = state.string_weak() + && let Some(letter) = letter.sym_weak() + && let Some(symbol) = symbol.string_weak() => + { + return Some((state, letter, symbol)); } _ => { _ = ctx.emit_error( @@ -636,11 +632,8 @@ impl<'a, 'b> Spanned<&'b ast::Tuple<'a>> { ctx: &mut Context<'a>, ) -> Option<(Spanned<&'a str>, &'b [Spanned>])> { match &self.0.0[..] { - [ - Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), - list, - ] => { - return Some((Spanned(state, *state_span), list.list_weak())); + [state, list] if let Some(state) = state.string_weak() => { + return Some((state, list.list_weak())); } _ => _ = ctx.emit_error("expected PDA transition (state, symbol|[symbol])", self.1), } diff --git a/automata/src/automatan/tm.rs b/automata/src/automatan/tm.rs index 7d53b98..9f16b48 100644 --- a/automata/src/automatan/tm.rs +++ b/automata/src/automatan/tm.rs @@ -253,7 +253,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if let Some(previous) = self @@ -282,7 +282,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if let Some(previous) = self @@ -311,7 +311,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> { return; }; for item in list { - let Some(ident) = item.expect_ident(self.ctx) else { + let Some(ident) = item.expect_ident_weak(self.ctx) else { continue; }; if self.states.contains_key(&State(ident)) { @@ -459,11 +459,11 @@ impl<'a> Spanned<&ast::Tuple<'a>> { ctx: &mut Context<'a>, ) -> Option<(Spanned<&'a str>, Spanned<&'a str>)> { match &self.0.0[..] { - [ - Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), - Spanned(ast::Item::Symbol(ast::Symbol::Ident(tape)), tape_span), - ] => { - return Some((Spanned(state, *state_span), Spanned(*tape, *tape_span))); + [state, tape] + if let Some(state) = state.string_weak() + && let Some(tape) = tape.string_weak() => + { + return Some((state, tape)); } _ => _ = ctx.emit_error("expected TM transition function (state, symbol)", self.1), } @@ -475,28 +475,25 @@ impl<'a> Spanned<&ast::Tuple<'a>> { ctx: &mut Context<'a>, ) -> Option<(Spanned<&'a str>, Spanned<&'a str>, Spanned)> { match &self.0.0[..] { - [ - Spanned(ast::Item::Symbol(ast::Symbol::Ident(state)), state_span), - Spanned(ast::Item::Symbol(ast::Symbol::Ident(tape)), tape_span), - Spanned(ast::Item::Symbol(direction), direction_span), - ] => { - let direction = match direction { + [state, tape, direction] + if let Some(state) = state.string_weak() + && let Some(tape) = tape.string_weak() + && let Some(direction) = direction.sym_weak() => + { + let direction_span = direction.1; + let direction = match direction.0 { ast::Symbol::Ident("left" | "L" | "<") => Direction::Left, ast::Symbol::Ident("right" | "R" | ">") => Direction::Right, ast::Symbol::Epsilon(_) | ast::Symbol::Ident("~") => Direction::None, ast::Symbol::Ident(ident) => { ctx.emit_error( format!("invalid direction specified '{ident}'"), - *direction_span, + direction.1, ); Direction::None } }; - return Some(( - Spanned(state, *state_span), - Spanned(*tape, *tape_span), - Spanned(direction, *direction_span), - )); + return Some((state, tape, Spanned(direction, direction_span))); } _ => { _ = ctx.emit_error( diff --git a/automata/src/loader/ast.rs b/automata/src/loader/ast.rs index 8e219a1..0e6e07d 100644 --- a/automata/src/loader/ast.rs +++ b/automata/src/loader/ast.rs @@ -23,7 +23,7 @@ pub enum Symbol<'a> { #[derive(Clone, Debug)] pub enum Item<'a> { Symbol(Symbol<'a>), - String(Cow<'a, str>), + String(&'a str), Tuple(Tuple<'a>), List(List<'a>), } @@ -50,7 +50,7 @@ pub struct List<'a>(pub Vec>>, pub ListKind); pub enum ProductionUnit<'a> { Epsilon(&'a str), Ident(&'a str), - String(Cow<'a, str>), + String(&'a str), } #[derive(Clone, Debug)] @@ -73,7 +73,7 @@ pub enum TopLevel<'a> { use crate::loader::{Context, log::LogSink}; impl<'a> Spanned> { - pub fn expect_symbol(&self, ctx: &mut Context<'a>) -> Option> { + pub fn expect_symbol_weak(&self, ctx: &mut Context<'a>) -> Option> { match &self.0 { Item::Symbol(sym) => return Some(*sym), Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1), @@ -83,15 +83,15 @@ impl<'a> Spanned> { 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 { Item::Symbol(Symbol::Ident(ident)) => return Some(ident), + Item::String(string) => _ = return Some(*string), 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::List(_) => _ = ctx.emit_error("expected ident found list", self.1), - Item::String(_) => _ = ctx.emit_error("expected ident found string", self.1), + Item::Tuple(_) => _ = ctx.emit_error("expected ident/string found tuple", self.1), + Item::List(_) => _ = ctx.emit_error("expected ident/string found list", self.1), } None } @@ -140,6 +140,25 @@ impl<'a> Spanned> { } } + pub fn string_weak(&self) -> Option> { + 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>> { + 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>> { match &self.0 { Item::Symbol(Symbol::Ident(_)) => { diff --git a/automata/src/loader/lexer.rs b/automata/src/loader/lexer.rs index 9cd51c4..710552d 100644 --- a/automata/src/loader/lexer.rs +++ b/automata/src/loader/lexer.rs @@ -174,7 +174,7 @@ impl<'a> std::iter::Iterator for Lexer<'a> { match self.consume() { Some('"') => { break Ok(Token::String( - &self.input[start + 1..self.position], + &self.input[start + 1..self.position-1], StringKind::Regular, escaped, )); diff --git a/automata/src/loader/log.rs b/automata/src/loader/log.rs index 742a7fa..15b59e0 100644 --- a/automata/src/loader/log.rs +++ b/automata/src/loader/log.rs @@ -231,11 +231,11 @@ impl<'a> Display for LogEntryDisplay<'a> { } for grapheme in line.graphemes(true) { if (span.0..span.1).contains(&index) { - for _ in 0..width(grapheme){ + for _ in 0..width(grapheme) { write!(f, "~")?; } } else { - for _ in 0..width(grapheme){ + for _ in 0..width(grapheme) { write!(f, " ")?; } } diff --git a/automata/src/loader/mod.rs b/automata/src/loader/mod.rs index e189edf..0b60bcf 100644 --- a/automata/src/loader/mod.rs +++ b/automata/src/loader/mod.rs @@ -152,7 +152,7 @@ pub fn parse_universal<'a>(ctx: &mut Context<'a>) -> Option> { fn parse_type<'a>(item: Option>>, ctx: &mut Context<'a>) -> Option { let (str, span) = match item { Some(S(TopLevel::Item(S("type", _), item @ S(_, span)), _)) => { - (item.expect_ident(ctx)?, span) + (item.expect_ident_weak(ctx)?, span) } Some(S(_, span)) => { ctx.emit_error("expected type= as first item", span) diff --git a/automata/src/loader/parser.rs b/automata/src/loader/parser.rs index c546777..7f8019e 100644 --- a/automata/src/loader/parser.rs +++ b/automata/src/loader/parser.rs @@ -141,7 +141,7 @@ impl<'a, 'b> Parser<'a, 'b> { S(Tuple(items), start.join(end)) } - fn parse_as_string(&mut self, tok: S>) -> S> { + fn parse_as_string(&mut self, tok: S>) -> S<&'a str> { let (r, k, e, s) = match tok { S(T::String(r, k, e), s) => (r, k, e, s), S(t, s) => { @@ -160,7 +160,7 @@ impl<'a, 'b> Parser<'a, 'b> { S(r.into(), s) } - fn parse_string(&mut self) -> S> { + fn parse_string(&mut self) -> S<&'a str> { let tok = self.next_token(); self.parse_as_string(tok) } diff --git a/web_lib/src/lib.rs b/web_lib/src/lib.rs index 274cc96..f626d60 100644 --- a/web_lib/src/lib.rs +++ b/web_lib/src/lib.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; 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; @@ -148,65 +151,99 @@ pub struct CompileResult { pub machine: Option, } -trait FixupSpan{ +trait FixupSpan { 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) { - match self{ + match self { Machine::Fa(fa) => fa.fixup(func), Machine::Pda(pda) => pda.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) { - self.alphabet.values_mut().for_each(|v| v.definition = func(v.definition)); - 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.function = func(e.function); - }); + self.alphabet + .values_mut() + .for_each(|v| v.definition = func(v.definition)); + 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.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) { - self.alphabet.values_mut().for_each(|v| v.definition = func(v.definition)); - self.states.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.function = func(e.function); - }); + self.alphabet + .values_mut() + .for_each(|v| v.definition = func(v.definition)); + self.states + .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.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) { - self.states.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.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.function = func(e.function); - }); + self.states + .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 + .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.function = func(e.function); + }); } } - - #[wasm_bindgen] pub fn compile(input: &str) -> CompileResult { let mut ctx = Context::new(input); let result = automata::loader::parse_universal(&mut ctx); 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() });