mirror of
https://github.com/ParkerTenBroeck/automata.git
synced 2026-06-06 21:24:06 -04:00
moved to deno to bundle website
This commit is contained in:
parent
c35d7a9192
commit
7629bdab6d
28 changed files with 1534 additions and 41961 deletions
|
|
@ -7,7 +7,7 @@ struct To(State, Vec<Symbol>);
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(unused)]
|
||||
pub struct TransitionTable {
|
||||
pub struct Npda {
|
||||
initial_state: State,
|
||||
initial_stack: Symbol,
|
||||
state_names: StateMap<String>,
|
||||
|
|
@ -19,7 +19,7 @@ pub struct TransitionTable {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NPDA {
|
||||
pub struct NpdaState {
|
||||
pub state: State,
|
||||
pub stack: Vec<Symbol>,
|
||||
pub position: usize,
|
||||
|
|
@ -27,26 +27,26 @@ pub struct NPDA {
|
|||
|
||||
pub struct Simulator {
|
||||
input: String,
|
||||
table: TransitionTable,
|
||||
running: Vec<NPDA>,
|
||||
machine: Npda,
|
||||
running: Vec<NpdaState>,
|
||||
}
|
||||
|
||||
pub enum SimulatorResult {
|
||||
Pending,
|
||||
Reject,
|
||||
Accept(NPDA),
|
||||
Accept(NpdaState),
|
||||
}
|
||||
|
||||
impl Simulator {
|
||||
pub fn begin(input: impl Into<String>, table: TransitionTable) -> Self {
|
||||
pub fn begin(input: impl Into<String>, machine: Npda) -> Self {
|
||||
Self {
|
||||
input: input.into(),
|
||||
running: vec![NPDA {
|
||||
state: table.initial_state,
|
||||
stack: vec![table.initial_stack],
|
||||
running: vec![NpdaState {
|
||||
state: machine.initial_state,
|
||||
stack: vec![machine.initial_stack],
|
||||
position: 0,
|
||||
}],
|
||||
table,
|
||||
machine,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ impl Simulator {
|
|||
};
|
||||
|
||||
for to in self
|
||||
.table
|
||||
.machine
|
||||
.transitions
|
||||
.get((npda.state, top))
|
||||
.and_then(|t| t.get(None))
|
||||
|
|
@ -68,7 +68,7 @@ impl Simulator {
|
|||
{
|
||||
let mut stack = npda.stack.clone();
|
||||
stack.extend_from_slice(&to.1);
|
||||
new.push(NPDA {
|
||||
new.push(NpdaState {
|
||||
state: to.0,
|
||||
stack,
|
||||
position: npda.position,
|
||||
|
|
@ -80,11 +80,11 @@ impl Simulator {
|
|||
.get(npda.position..)
|
||||
.and_then(|c| c.chars().next())
|
||||
else {
|
||||
if let Some(final_states) = &self.table.final_states
|
||||
if let Some(final_states) = &self.machine.final_states
|
||||
&& final_states.get(npda.state).copied().unwrap_or_default()
|
||||
{
|
||||
return SimulatorResult::Accept(npda.clone());
|
||||
} else if npda.stack == [self.table.initial_stack] {
|
||||
} else if npda.stack == [self.machine.initial_stack] {
|
||||
return SimulatorResult::Accept(npda.clone());
|
||||
} else {
|
||||
continue;
|
||||
|
|
@ -92,7 +92,7 @@ impl Simulator {
|
|||
};
|
||||
|
||||
for to in self
|
||||
.table
|
||||
.machine
|
||||
.transitions
|
||||
.get((npda.state, top))
|
||||
.and_then(|t| t.get(Some(next)))
|
||||
|
|
@ -101,7 +101,7 @@ impl Simulator {
|
|||
{
|
||||
let mut stack = npda.stack.clone();
|
||||
stack.extend_from_slice(&to.1);
|
||||
new.push(NPDA {
|
||||
new.push(NpdaState {
|
||||
state: to.0,
|
||||
stack,
|
||||
position: npda.position + next.len_utf8(),
|
||||
|
|
@ -120,26 +120,14 @@ impl Simulator {
|
|||
// ------ parser/semantics
|
||||
|
||||
use crate::loader::{
|
||||
DELTA_LOWER, GAMMA_UPPER, SIGMA_UPPER, Spanned,
|
||||
ast::{self, Symbol as Sym},
|
||||
lexer::Lexer,
|
||||
log::Logs,
|
||||
parser::Parser,
|
||||
Context, DELTA_LOWER, GAMMA_UPPER, SIGMA_UPPER, Spanned, ast::{self, Symbol as Sym}
|
||||
};
|
||||
|
||||
impl TransitionTable {
|
||||
pub fn load_table<'a>(input: &'a str) -> Result<(TransitionTable, Logs<'a>), Logs<'a>> {
|
||||
let (ast, logs) = Parser::new(Lexer::new(input)).parse_elements();
|
||||
if logs.contains_errors() {
|
||||
return Err(logs);
|
||||
}
|
||||
Self::load_from_ast(&ast, logs)
|
||||
}
|
||||
|
||||
impl Npda {
|
||||
pub fn load_from_ast<'a>(
|
||||
ast: &Vec<Spanned<ast::TopLevel<'a>>>,
|
||||
mut logs: Logs<'a>,
|
||||
) -> Result<(TransitionTable, Logs<'a>), Logs<'a>> {
|
||||
items: impl Iterator<Item = Spanned<ast::TopLevel<'a>>>,
|
||||
ctx: &mut Context<'a>
|
||||
) -> Option<Npda> {
|
||||
let mut initial_state = None;
|
||||
let mut initial_stack = None;
|
||||
|
||||
|
|
@ -150,141 +138,141 @@ impl TransitionTable {
|
|||
|
||||
let mut transitions_map = HashMap::new();
|
||||
|
||||
for Spanned(element, span) in ast {
|
||||
for Spanned(element, span) in items {
|
||||
use Spanned as S;
|
||||
use ast::TopLevel as TL;
|
||||
match element {
|
||||
TL::Item(S("Q", _), list) => {
|
||||
if !states.is_empty() {
|
||||
logs.emit_error("states already set", *span);
|
||||
ctx.emit_error("states already set", span);
|
||||
}
|
||||
let Some(list) = list.expect_set(&mut logs) else {
|
||||
let Some(list) = list.expect_set(ctx) else {
|
||||
continue;
|
||||
};
|
||||
for item in list {
|
||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||
let Some(ident) = item.expect_ident(ctx) else {
|
||||
continue;
|
||||
};
|
||||
let state = match states.len().try_into() {
|
||||
Ok(ok) => State(ok),
|
||||
Err(_) => {
|
||||
logs.emit_error("too many states defined", item.1);
|
||||
ctx.emit_error("too many states defined", item.1);
|
||||
State(0)
|
||||
}
|
||||
};
|
||||
if states.insert(ident, state).is_some() {
|
||||
logs.emit_error("state redefined", item.1);
|
||||
ctx.emit_error("state redefined", item.1);
|
||||
}
|
||||
}
|
||||
|
||||
if list.is_empty() {
|
||||
logs.emit_error("states cannot be empty", *span);
|
||||
ctx.emit_error("states cannot be empty", span);
|
||||
}
|
||||
}
|
||||
TL::Item(S("E" | SIGMA_UPPER | "sigma", _), list) => {
|
||||
if !alphabet.is_empty() {
|
||||
logs.emit_error("alphabet already set", *span);
|
||||
ctx.emit_error("alphabet already set", span);
|
||||
}
|
||||
let Some(list) = list.expect_set(&mut logs) else {
|
||||
let Some(list) = list.expect_set(ctx) else {
|
||||
continue;
|
||||
};
|
||||
for item in list {
|
||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||
let Some(ident) = item.expect_ident(ctx) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if ident.chars().count() != 1 {
|
||||
logs.emit_error("letter cannot be longer than one char", item.1);
|
||||
ctx.emit_error("letter cannot be longer than one char", item.1);
|
||||
}
|
||||
|
||||
if !alphabet.insert(ident.chars().next().unwrap_or_default()) {
|
||||
logs.emit_error("letter redefined", item.1);
|
||||
ctx.emit_error("letter redefined", item.1);
|
||||
}
|
||||
}
|
||||
if list.is_empty() {
|
||||
logs.emit_error("alphabet cannot be empty", *span);
|
||||
ctx.emit_error("alphabet cannot be empty", span);
|
||||
}
|
||||
}
|
||||
TL::Item(S("F", _), list) => {
|
||||
if final_states.is_some() {
|
||||
logs.emit_error("final states already set", *span);
|
||||
ctx.emit_error("final states already set", span);
|
||||
}
|
||||
let mut map = HashSet::new();
|
||||
let Some(list) = list.expect_set(&mut logs) else {
|
||||
let Some(list) = list.expect_set(ctx) else {
|
||||
continue;
|
||||
};
|
||||
for item in list {
|
||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||
let Some(ident) = item.expect_ident(ctx) else {
|
||||
continue;
|
||||
};
|
||||
if let Some(state) = states.get(ident) {
|
||||
if !map.insert(*state) {
|
||||
logs.emit_error("final state redefined", item.1);
|
||||
ctx.emit_error("final state redefined", item.1);
|
||||
}
|
||||
} else {
|
||||
logs.emit_error("final state not defined in set of states", item.1);
|
||||
ctx.emit_error("final state not defined in set of states", item.1);
|
||||
}
|
||||
}
|
||||
final_states = Some(map);
|
||||
}
|
||||
TL::Item(S("T" | GAMMA_UPPER | "gamma", _), list) => {
|
||||
if !stack_symbols.is_empty() {
|
||||
logs.emit_error("stack symbols already set", *span);
|
||||
ctx.emit_error("stack symbols already set", span);
|
||||
}
|
||||
let Some(list) = list.expect_set(&mut logs) else {
|
||||
let Some(list) = list.expect_set(ctx) else {
|
||||
continue;
|
||||
};
|
||||
for item in list {
|
||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||
let Some(ident) = item.expect_ident(ctx) else {
|
||||
continue;
|
||||
};
|
||||
let symbol = match stack_symbols.len().try_into() {
|
||||
Ok(ok) => Symbol(ok),
|
||||
Err(_) => {
|
||||
logs.emit_error("too many stack symbols defined", item.1);
|
||||
ctx.emit_error("too many stack symbols defined", item.1);
|
||||
Symbol(0)
|
||||
}
|
||||
};
|
||||
if stack_symbols.insert(ident, symbol).is_some() {
|
||||
logs.emit_error("stack symbol redefined", item.1);
|
||||
ctx.emit_error("stack symbol redefined", item.1);
|
||||
}
|
||||
}
|
||||
|
||||
if list.is_empty() {
|
||||
logs.emit_error("stack symbols cannot be empty", *span);
|
||||
ctx.emit_error("stack symbols cannot be empty", span);
|
||||
}
|
||||
}
|
||||
TL::Item(S("I" | "q0", _), S(src, src_d)) => match src {
|
||||
ast::Item::Symbol(Sym::Ident(ident)) => {
|
||||
if initial_state.is_some() {
|
||||
logs.emit_error("initial state already set", *span);
|
||||
ctx.emit_error("initial state already set", span);
|
||||
}
|
||||
if let Some(initial) = states.get(ident) {
|
||||
initial_state = Some(*initial)
|
||||
} else {
|
||||
logs.emit_error("initial state symbol not defined as a state", *src_d);
|
||||
ctx.emit_error("initial state symbol not defined as a state", src_d);
|
||||
}
|
||||
}
|
||||
_ => logs.emit_error("expected ident", *src_d),
|
||||
_ => ctx.emit_error("expected ident", src_d),
|
||||
},
|
||||
TL::Item(S("S" | "z0", _), S(src, src_d)) => match src {
|
||||
ast::Item::Symbol(Sym::Ident(ident)) => {
|
||||
if initial_stack.is_some() {
|
||||
logs.emit_error("initial stack already set", *span);
|
||||
ctx.emit_error("initial stack already set", span);
|
||||
}
|
||||
if let Some(initial) = stack_symbols.get(ident) {
|
||||
initial_stack = Some(*initial)
|
||||
} else {
|
||||
logs.emit_error(
|
||||
ctx.emit_error(
|
||||
"initial stack symbol not defined as a stack symbol",
|
||||
*src_d,
|
||||
src_d,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => logs.emit_error("expected ident", *src_d),
|
||||
_ => ctx.emit_error("expected ident", src_d),
|
||||
},
|
||||
TL::Item(S(name, dest_s), _) => {
|
||||
logs.emit_error(format!("unknown item {name:?}, expected 'Q' | 'E' | '{SIGMA_UPPER}' | 'sigma' | 'F' | 'T' | '{GAMMA_UPPER}' | 'gamma' | 'I' | 'q0' | 'S' | 'z0'"), *dest_s);
|
||||
ctx.emit_error(format!("unknown item {name:?}, expected 'Q' | 'E' | '{SIGMA_UPPER}' | 'sigma' | 'F' | 'T' | '{GAMMA_UPPER}' | 'gamma' | 'I' | 'q0' | 'S' | 'z0'"), dest_s);
|
||||
}
|
||||
|
||||
TL::TransitionFunc(
|
||||
|
|
@ -293,16 +281,16 @@ impl TransitionTable {
|
|||
) => {
|
||||
let list = list.set_weak();
|
||||
let Some((state, letter, stack_symbol)) =
|
||||
tuple.as_ref().expect_npda_transition_function(&mut logs)
|
||||
tuple.as_ref().expect_npda_transition_function(ctx)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let Some(state) = states.get(state.0).copied() else {
|
||||
logs.emit_error("transition state not defined as state", state.1);
|
||||
ctx.emit_error("transition state not defined as state", state.1);
|
||||
continue;
|
||||
};
|
||||
let Some(stack_symbol) = stack_symbols.get(stack_symbol.0).copied() else {
|
||||
logs.emit_error(
|
||||
ctx.emit_error(
|
||||
"transition stack symbol not defined as stack symbol",
|
||||
stack_symbol.1,
|
||||
);
|
||||
|
|
@ -316,14 +304,14 @@ impl TransitionTable {
|
|||
&& val.chars().count() == 1
|
||||
{
|
||||
if !alphabet.contains(&char) {
|
||||
logs.emit_error(
|
||||
ctx.emit_error(
|
||||
"transition letter not defined in alphabet",
|
||||
letter.1,
|
||||
);
|
||||
}
|
||||
Some(char)
|
||||
} else {
|
||||
logs.emit_error(
|
||||
ctx.emit_error(
|
||||
"transition letter can only be single character",
|
||||
letter.1,
|
||||
);
|
||||
|
|
@ -334,14 +322,14 @@ impl TransitionTable {
|
|||
|
||||
for item in list {
|
||||
let Some((next_state, stack)) = item
|
||||
.expect_tuple(&mut logs)
|
||||
.and_then(|item| item.expect_npda_transition(&mut logs))
|
||||
.expect_tuple(ctx)
|
||||
.and_then(|item| item.expect_npda_transition(ctx))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(next_state) = states.get(next_state.0).copied() else {
|
||||
logs.emit_error("transition state not defined as state", next_state.1);
|
||||
ctx.emit_error("transition state not defined as state", next_state.1);
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -352,10 +340,10 @@ impl TransitionTable {
|
|||
if matches!(symbol.0, ast::Item::Symbol(Sym::Epsilon)) {
|
||||
return None;
|
||||
}
|
||||
let ident = symbol.expect_ident(&mut logs)?;
|
||||
let ident = symbol.expect_ident(ctx)?;
|
||||
|
||||
let Some(symbol) = stack_symbols.get(ident).copied() else {
|
||||
logs.emit_error(
|
||||
ctx.emit_error(
|
||||
"transition stack symbol not defined",
|
||||
symbol.1,
|
||||
);
|
||||
|
|
@ -370,46 +358,46 @@ impl TransitionTable {
|
|||
.or_insert(HashSet::new())
|
||||
.insert((next_state, stack))
|
||||
{
|
||||
logs.emit_warning("duplicate transition", item.1);
|
||||
ctx.emit_warning("duplicate transition", item.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
TL::TransitionFunc(S((S(name, _), _), dest_s), _) => {
|
||||
logs.emit_error(
|
||||
ctx.emit_error(
|
||||
format!("unknown function {name:?}, expected 'd' | 'delta' | '{DELTA_LOWER}'"),
|
||||
*dest_s,
|
||||
dest_s,
|
||||
);
|
||||
}
|
||||
|
||||
TL::ProductionRule(_, _) => {
|
||||
logs.emit_error("unexpected production rule", *span);
|
||||
ctx.emit_error("unexpected production rule", span);
|
||||
}
|
||||
TL::Table() => logs.emit_error("unexpected table", *span),
|
||||
TL::Table() => ctx.emit_error("unexpected table", span),
|
||||
}
|
||||
}
|
||||
|
||||
if stack_symbols.is_empty() {
|
||||
logs.emit_error_locless("stack symbols never defined");
|
||||
ctx.emit_error_locless("stack symbols never defined");
|
||||
}
|
||||
|
||||
if alphabet.is_empty() {
|
||||
logs.emit_error_locless("alphabet never defined");
|
||||
ctx.emit_error_locless("alphabet never defined");
|
||||
}
|
||||
|
||||
if states.is_empty() {
|
||||
logs.emit_error_locless("states never defined");
|
||||
ctx.emit_error_locless("states never defined");
|
||||
}
|
||||
|
||||
let initial_stack = match initial_stack {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
if let Some(initial) = stack_symbols.get("z0") {
|
||||
logs.emit_warning_locless(
|
||||
ctx.emit_warning_locless(
|
||||
"initial stack symbol not defined, defaulting to 'z0'",
|
||||
);
|
||||
*initial
|
||||
} else {
|
||||
logs.emit_error_locless("initial stack symbol not defined");
|
||||
ctx.emit_error_locless("initial stack symbol not defined");
|
||||
Symbol(0)
|
||||
}
|
||||
}
|
||||
|
|
@ -419,10 +407,10 @@ impl TransitionTable {
|
|||
Some(some) => some,
|
||||
None => {
|
||||
if let Some(initial) = states.get("q0") {
|
||||
logs.emit_warning_locless("initial state not defined, defaulting to 'q0'");
|
||||
ctx.emit_warning_locless("initial state not defined, defaulting to 'q0'");
|
||||
*initial
|
||||
} else {
|
||||
logs.emit_error_locless("initial state not defined");
|
||||
ctx.emit_error_locless("initial state not defined");
|
||||
State(0)
|
||||
}
|
||||
}
|
||||
|
|
@ -461,7 +449,11 @@ impl TransitionTable {
|
|||
}
|
||||
}
|
||||
|
||||
let table = TransitionTable {
|
||||
if ctx.contains_errors(){
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Npda {
|
||||
initial_state,
|
||||
initial_stack,
|
||||
state_names,
|
||||
|
|
@ -469,8 +461,6 @@ impl TransitionTable {
|
|||
alphabet,
|
||||
final_states,
|
||||
transitions,
|
||||
};
|
||||
|
||||
Ok((table, logs))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,36 +59,36 @@ pub enum TopLevel<'a> {
|
|||
Table(),
|
||||
}
|
||||
|
||||
use crate::loader::log::Logs;
|
||||
use crate::loader::Context;
|
||||
|
||||
impl<'a> Spanned<Item<'a>> {
|
||||
pub fn expect_ident(&self, logs: &mut Logs<'a>) -> Option<&'a str> {
|
||||
pub fn expect_ident(&self, ctx: &mut Context<'a>) -> Option<&'a str> {
|
||||
match &self.0 {
|
||||
Item::Symbol(Symbol::Ident(ident)) => return Some(ident),
|
||||
Item::Symbol(Symbol::Epsilon) => {
|
||||
logs.emit_error("expected ident found epsilon", self.1)
|
||||
ctx.emit_error("expected ident found epsilon", self.1)
|
||||
}
|
||||
Item::Tuple(_) => logs.emit_error("expected ident found tuple", self.1),
|
||||
Item::List(_) => logs.emit_error("expected ident found list", self.1),
|
||||
Item::Tuple(_) => ctx.emit_error("expected ident found tuple", self.1),
|
||||
Item::List(_) => ctx.emit_error("expected ident found list", self.1),
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn expect_set(&self, logs: &mut Logs<'a>) -> Option<&[Spanned<Item<'a>>]> {
|
||||
pub fn expect_set(&self, ctx: &mut Context<'a>) -> Option<&[Spanned<Item<'a>>]> {
|
||||
match &self.0 {
|
||||
Item::Symbol(Symbol::Ident(_)) => logs.emit_error("expected set found ident", self.1),
|
||||
Item::Symbol(Symbol::Epsilon) => logs.emit_error("expected set found epsilon", self.1),
|
||||
Item::Tuple(_) => logs.emit_error("expected set found tuple", self.1),
|
||||
Item::Symbol(Symbol::Ident(_)) => ctx.emit_error("expected set found ident", self.1),
|
||||
Item::Symbol(Symbol::Epsilon) => ctx.emit_error("expected set found epsilon", self.1),
|
||||
Item::Tuple(_) => ctx.emit_error("expected set found tuple", self.1),
|
||||
Item::List(list) => return Some(&list.0),
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn expect_list(&self, logs: &mut Logs<'a>) -> Option<&[Spanned<Item<'a>>]> {
|
||||
pub fn expect_list(&self, ctx: &mut Context<'a>) -> Option<&[Spanned<Item<'a>>]> {
|
||||
match &self.0 {
|
||||
Item::Symbol(Symbol::Ident(_)) => logs.emit_error("expected list found ident", self.1),
|
||||
Item::Symbol(Symbol::Epsilon) => logs.emit_error("expected list found epsilon", self.1),
|
||||
Item::Tuple(_) => logs.emit_error("expected list found tuple", self.1),
|
||||
Item::Symbol(Symbol::Ident(_)) => ctx.emit_error("expected list found ident", self.1),
|
||||
Item::Symbol(Symbol::Epsilon) => ctx.emit_error("expected list found epsilon", self.1),
|
||||
Item::Tuple(_) => ctx.emit_error("expected list found tuple", self.1),
|
||||
Item::List(list) => return Some(&list.0),
|
||||
}
|
||||
None
|
||||
|
|
@ -108,34 +108,34 @@ impl<'a> Spanned<Item<'a>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_tuple(&self, logs: &mut Logs<'a>) -> Option<Spanned<&Tuple<'a>>> {
|
||||
pub fn expect_tuple(&self, ctx: &mut Context<'a>) -> Option<Spanned<&Tuple<'a>>> {
|
||||
match &self.0 {
|
||||
Item::Symbol(Symbol::Ident(_)) => logs.emit_error("expected tuple found ident", self.1),
|
||||
Item::Symbol(Symbol::Ident(_)) => ctx.emit_error("expected tuple found ident", self.1),
|
||||
Item::Symbol(Symbol::Epsilon) => {
|
||||
logs.emit_error("expected tuple found epsilon", self.1)
|
||||
ctx.emit_error("expected tuple found epsilon", self.1)
|
||||
}
|
||||
Item::Tuple(tuple) => return Some(Spanned(tuple, self.1)),
|
||||
Item::List(_) => logs.emit_error("expected tuple found list", self.1),
|
||||
Item::List(_) => ctx.emit_error("expected tuple found list", self.1),
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Spanned<&'b Tuple<'a>> {
|
||||
pub fn expect_dfa_transition(&self, _: &mut Logs<'a>) -> ! {
|
||||
pub fn expect_dfa_transition(&self, _: &mut Context<'a>) -> ! {
|
||||
todo!()
|
||||
}
|
||||
pub fn expect_nfa_transition(&self, _: &mut Logs<'a>) -> ! {
|
||||
pub fn expect_nfa_transition(&self, _: &mut Context<'a>) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn expect_dpda_transition(&self, _: &mut Logs<'a>) -> ! {
|
||||
pub fn expect_dpda_transition(&self, _: &mut Context<'a>) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn expect_npda_transition_function(
|
||||
&self,
|
||||
logs: &mut Logs<'a>,
|
||||
ctx: &mut Context<'a>,
|
||||
) -> Option<(Spanned<&'a str>, Spanned<Symbol<'a>>, Spanned<&'a str>)> {
|
||||
match &self.0.0[..] {
|
||||
[
|
||||
|
|
@ -149,7 +149,7 @@ impl<'a, 'b> Spanned<&'b Tuple<'a>> {
|
|||
Spanned(symbol, *symbol_span),
|
||||
));
|
||||
}
|
||||
_ => logs.emit_error(
|
||||
_ => ctx.emit_error(
|
||||
"expected NPDA transition function (ident, ident|~, ident)",
|
||||
self.1,
|
||||
),
|
||||
|
|
@ -158,7 +158,7 @@ impl<'a, 'b> Spanned<&'b Tuple<'a>> {
|
|||
}
|
||||
pub fn expect_npda_transition(
|
||||
&self,
|
||||
logs: &mut Logs<'a>,
|
||||
ctx: &mut Context<'a>,
|
||||
) -> Option<(Spanned<&'a str>, &'b [Spanned<Item<'a>>])> {
|
||||
match &self.0.0[..] {
|
||||
[
|
||||
|
|
@ -167,15 +167,15 @@ impl<'a, 'b> Spanned<&'b Tuple<'a>> {
|
|||
] => {
|
||||
return Some((Spanned(state, *state_span), list.list_weak()));
|
||||
}
|
||||
_ => logs.emit_error("expected NPDA transition (ident, item|[item])", self.1),
|
||||
_ => ctx.emit_error("expected NPDA transition (ident, item|[item])", self.1),
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn expect_tm_transition(&self, _: &mut Logs<'a>) -> ! {
|
||||
pub fn expect_tm_transition(&self, _: &Context<'a>) -> ! {
|
||||
todo!()
|
||||
}
|
||||
pub fn expect_ntm_transition(&self, _: &mut Logs<'a>) -> ! {
|
||||
pub fn expect_ntm_transition(&self, _: &Context<'a>) -> ! {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,6 @@ impl<'a> std::fmt::Display for Token<'a> {
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Lexer<'a> {
|
||||
input: &'a str,
|
||||
|
||||
start: usize,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +71,6 @@ impl<'a> Lexer<'a> {
|
|||
pub fn new(input: &'a str) -> Self {
|
||||
Self {
|
||||
input,
|
||||
start: 0,
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -96,13 +93,6 @@ impl<'a> Lexer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn eof_span(&self) -> Span {
|
||||
Span(self.input.len(), self.input.len())
|
||||
}
|
||||
|
||||
pub fn input(&self) -> &'a str {
|
||||
self.input
|
||||
}
|
||||
}
|
||||
|
||||
fn begin_ident(c: char) -> bool {
|
||||
|
|
@ -121,16 +111,15 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
|
|||
&& c.is_whitespace()
|
||||
{
|
||||
if c == '\n'{
|
||||
self.start = self.position;
|
||||
let start = self.position;
|
||||
self.consume();
|
||||
let res = Some(Spanned(Ok(Token::LineEnd), Span(self.start, self.position)));
|
||||
self.start = self.position;
|
||||
let res = Some(Spanned(Ok(Token::LineEnd), Span(start, self.position)));
|
||||
return res;
|
||||
}else{
|
||||
self.consume();
|
||||
}
|
||||
}
|
||||
self.start = self.position;
|
||||
let start = self.position;
|
||||
|
||||
let res = match self.consume()? {
|
||||
'(' => Ok(Token::LPar),
|
||||
|
|
@ -163,8 +152,7 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
|
|||
'/' => match self.consume() {
|
||||
Some('/') => loop {
|
||||
if let Some('\n') | None = self.consume() {
|
||||
self.backtrack();
|
||||
break Ok(Token::Comment(&self.input[self.start + 2..=self.position]));
|
||||
break Ok(Token::Comment(&self.input[start + 2..self.position]));
|
||||
}
|
||||
},
|
||||
Some('*') => loop {
|
||||
|
|
@ -172,7 +160,7 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
|
|||
Some('*') if self.peek() == Some('/') => {
|
||||
self.consume();
|
||||
break Ok(Token::Comment(
|
||||
&self.input[self.start + 2..self.position - 2],
|
||||
&self.input[start + 2..self.position - 2],
|
||||
));
|
||||
}
|
||||
Some(_) => {}
|
||||
|
|
@ -191,16 +179,15 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
|
|||
Some(c) if continue_ident(c) => {}
|
||||
Some(_) => {
|
||||
self.backtrack();
|
||||
break Ok(Token::Ident(&self.input[self.start..self.position]));
|
||||
break Ok(Token::Ident(&self.input[start..self.position]));
|
||||
}
|
||||
None => break Ok(Token::Ident(&self.input[self.start..self.position])),
|
||||
None => break Ok(Token::Ident(&self.input[start..self.position])),
|
||||
}
|
||||
},
|
||||
|
||||
c => Err(Error::InvalidChar(c)),
|
||||
};
|
||||
let span = Span(self.start, self.position);
|
||||
self.start = self.position;
|
||||
let span = Span(start, self.position);
|
||||
Some(Spanned(res, span))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
use std::{borrow::Cow, fmt::Display};
|
||||
use std::{fmt::Display};
|
||||
|
||||
use crate::loader::Span;
|
||||
|
||||
pub struct Logs<'a> {
|
||||
pub struct Logs {
|
||||
logs: Vec<LogEntry>,
|
||||
src: Cow<'a, str>,
|
||||
has_error: bool,
|
||||
}
|
||||
|
||||
impl<'a> Logs<'a> {
|
||||
pub fn new(src: impl Into<Cow<'a, str>>) -> Self {
|
||||
impl Logs {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
logs: Vec::new(),
|
||||
src: src.into(),
|
||||
has_error: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -66,9 +64,9 @@ impl<'a> Logs<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn displayable(&self) -> impl Iterator<Item = LogEntryDisplay<'_>> {
|
||||
pub fn displayable_with<'a>(&'a self, src: &'a str) -> impl Iterator<Item = LogEntryDisplay<'a>> {
|
||||
self.logs.iter().map(|entry| LogEntryDisplay {
|
||||
src: &self.src,
|
||||
src,
|
||||
entry,
|
||||
})
|
||||
}
|
||||
|
|
@ -80,9 +78,11 @@ impl<'a> Logs<'a> {
|
|||
pub fn into_entries(self) -> impl Iterator<Item = LogEntry> {
|
||||
self.logs.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn src(&self) -> &str {
|
||||
&self.src
|
||||
impl Default for Logs {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
use crate::{automata::npda, loader::ast::TopLevel};
|
||||
|
||||
pub mod ast;
|
||||
pub mod lexer;
|
||||
pub mod log;
|
||||
pub mod parser;
|
||||
|
||||
pub const EPSILON_LOWER: &str = "Ɛ";
|
||||
pub const EPSILON_LOWER_MATH: &str = "𝛆";
|
||||
pub const DELTA_LOWER: &str = "δ";
|
||||
pub const SIGMA_UPPER: &str = "Σ";
|
||||
pub const GAMMA_UPPER: &str = "Γ";
|
||||
|
|
@ -28,3 +31,118 @@ impl<T> Spanned<T> {
|
|||
Spanned(&self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Context<'a>{
|
||||
logs: log::Logs,
|
||||
src: &'a str
|
||||
}
|
||||
|
||||
impl<'a> Context<'a>{
|
||||
pub fn new(src: &'a str) -> Self{
|
||||
Self { logs: log::Logs::new(), src }
|
||||
}
|
||||
|
||||
pub fn src(&self) -> &'a str{
|
||||
self.src
|
||||
}
|
||||
|
||||
pub fn logs_display(&self) -> impl Iterator<Item = log::LogEntryDisplay<'_>>{
|
||||
self.logs.displayable_with(self.src)
|
||||
}
|
||||
|
||||
pub fn eof(&self) -> Span{
|
||||
Span(self.src.len(), self.src.len())
|
||||
}
|
||||
|
||||
pub fn emit(&mut self, entry: log::LogEntry) {
|
||||
self.logs.emit(entry);
|
||||
}
|
||||
|
||||
pub fn emit_error_locless(&mut self, msg: impl Into<String>) {
|
||||
self.logs.emit_error_locless(msg);
|
||||
}
|
||||
|
||||
pub fn emit_error(&mut self, msg: impl Into<String>, span: Span) {
|
||||
self.logs.emit_error(msg, span);
|
||||
}
|
||||
|
||||
pub fn emit_warning(&mut self, msg: impl Into<String>, span: Span) {
|
||||
self.logs.emit_warning(msg, span);
|
||||
}
|
||||
|
||||
pub fn emit_warning_locless(&mut self, msg: impl Into<String>) {
|
||||
self.logs.emit_warning_locless(msg);
|
||||
}
|
||||
|
||||
pub fn emit_info(&mut self, msg: impl Into<String>, span: Span) {
|
||||
self.logs.emit_info(msg, span);
|
||||
}
|
||||
|
||||
pub fn contains_errors(&self) -> bool {
|
||||
self.logs.contains_errors()
|
||||
}
|
||||
|
||||
pub fn into_logs(self) -> log::Logs{
|
||||
self.logs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub enum Machine{
|
||||
Npda(npda::Npda)
|
||||
}
|
||||
|
||||
pub fn parse_universal(ctx: &mut Context<'_>) -> Option<Machine> {
|
||||
let mut items = parser::Parser::new(ctx).collect::<Vec<_>>().into_iter();
|
||||
if ctx.logs.contains_errors(){
|
||||
return None;
|
||||
}
|
||||
|
||||
use Spanned as S;
|
||||
|
||||
enum Type{
|
||||
Dfa,
|
||||
Nfa,
|
||||
Dpda,
|
||||
Npda,
|
||||
Tm,
|
||||
Ntm
|
||||
}
|
||||
|
||||
fn parse_type<'a>(item: Option<S<TopLevel<'a>>>, ctx: &mut Context<'a>) -> Option<Type>{
|
||||
let (str, span) = match item{
|
||||
Some(S(TopLevel::Item(S("type", _), item@S(_,span)), _)) => (item.expect_ident(ctx)?, span),
|
||||
Some(S(_, span)) => {
|
||||
ctx.emit_error("expected type=<type> as first item", span);
|
||||
return None;
|
||||
}
|
||||
None => {
|
||||
ctx.emit_error("expected type=<type> as first item", ctx.eof());
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(match str{
|
||||
"dfa"|"DFA" => Type::Dfa,
|
||||
"nfa"|"NFA" => Type::Nfa,
|
||||
"dpda"|"DPDA" => Type::Dpda,
|
||||
"npdaA"|"NPDA" => Type::Npda,
|
||||
"tm"|"TM" => Type::Tm,
|
||||
"ntm"|"NTM" => Type::Ntm,
|
||||
_ => {
|
||||
ctx.emit_error("unknown type, expected 'DFA' | 'NFA' | 'DPDA' | 'NPDA' | 'TM' | 'NTM'", span);
|
||||
return None;
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Some(match parse_type(items.next(), ctx)?{
|
||||
Type::Dfa => todo!(),
|
||||
Type::Nfa => todo!(),
|
||||
Type::Dpda => todo!(),
|
||||
Type::Npda => Machine::Npda(npda::Npda::load_from_ast(items, ctx)?),
|
||||
Type::Tm => todo!(),
|
||||
Type::Ntm => todo!(),
|
||||
})
|
||||
}
|
||||
|
|
@ -1,283 +1,242 @@
|
|||
use crate::loader::log::{LogEntryDisplay, Logs};
|
||||
use crate::loader::{EPSILON_LOWER, Span, Spanned};
|
||||
use crate::loader::{Context, Span};
|
||||
|
||||
use super::lexer::Token as T;
|
||||
use crate::loader::Spanned as S;
|
||||
|
||||
use super::ast::*;
|
||||
use super::lexer::{Lexer, Token};
|
||||
use super::lexer::Lexer;
|
||||
|
||||
pub struct Parser<'a> {
|
||||
pub struct Parser<'a, 'b> {
|
||||
lexer: Lexer<'a>,
|
||||
peek: Option<Spanned<Token<'a>>>,
|
||||
logs: Logs<'a>,
|
||||
peek: Option<S<T<'a>>>,
|
||||
ctx: &'b mut Context<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn new(lexer: Lexer<'a>) -> Self {
|
||||
Parser {
|
||||
logs: Logs::new(lexer.input()),
|
||||
peek: None,
|
||||
lexer,
|
||||
}
|
||||
}
|
||||
impl<'a, 'b> Iterator for Parser<'a, 'b> {
|
||||
type Item = S<TopLevel<'a>>;
|
||||
|
||||
fn eof(&self) -> Span {
|
||||
self.lexer.eof_span()
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.next_element()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Parser<'a, 'b> {
|
||||
pub fn new(ctx: &'b mut Context<'a>) -> Self {
|
||||
Parser {
|
||||
lexer: Lexer::new(ctx.src()),
|
||||
ctx,
|
||||
peek: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn advance_line(&mut self) {
|
||||
if self.peek_token().is_none(){
|
||||
return;
|
||||
}
|
||||
|
||||
if self.expect_token(Token::LineEnd).0 {
|
||||
if self.expect_token(T::LineEnd).0 {
|
||||
self.peek = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn next_token(&mut self) -> Option<Spanned<Token<'a>>> {
|
||||
fn next_token_optional(&mut self) -> Option<S<T<'a>>> {
|
||||
match self.peek {
|
||||
Some(Spanned(Token::LineEnd, _)) => return self.peek,
|
||||
Some(S(T::LineEnd, _)) => return self.peek,
|
||||
Some(_) => return self.peek.take(),
|
||||
_ => {}
|
||||
}
|
||||
loop {
|
||||
match self.lexer.next() {
|
||||
Some(Spanned(Ok(Token::Comment(_)), _)) => {}
|
||||
Some(Spanned(Ok(Token::LineEnd), span)) => {
|
||||
self.peek = Some(Spanned(Token::LineEnd, span));
|
||||
Some(S(Ok(T::Comment(_)), _)) => {}
|
||||
Some(S(Ok(T::LineEnd), span)) => {
|
||||
self.peek = Some(S(T::LineEnd, span));
|
||||
return self.peek;
|
||||
}
|
||||
Some(Spanned(Ok(ok), r)) => return Some(Spanned(ok, r)),
|
||||
Some(Spanned(Err(err), span)) => {
|
||||
self.logs.emit_error(format!("lexer: {err:?}"), span)
|
||||
}
|
||||
Some(S(Ok(ok), r)) => return Some(S(ok, r)),
|
||||
Some(S(Err(err), span)) => self.ctx.emit_error(format!("lexer: {err:?}"), span),
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn peek_token(&mut self) -> Option<Spanned<Token<'a>>> {
|
||||
fn peek_token_optional(&mut self) -> Option<S<T<'a>>> {
|
||||
if self.peek.is_none() {
|
||||
self.peek = self.next_token();
|
||||
self.peek = self.next_token_optional();
|
||||
}
|
||||
self.peek
|
||||
}
|
||||
|
||||
fn expect_token(&mut self, expected: Token<'a>) -> (bool, Span) {
|
||||
if let Some(Spanned(token, span)) = self.peek_token() {
|
||||
if token != expected {
|
||||
self.logs.emit_error(
|
||||
format!("unexpected {:#}, expected {:}", token, expected),
|
||||
span,
|
||||
);
|
||||
(false, span)
|
||||
} else {
|
||||
fn next_token(&mut self) -> S<T<'a>> {
|
||||
self.next_token_optional()
|
||||
.unwrap_or(S(T::LineEnd, self.ctx.eof()))
|
||||
}
|
||||
|
||||
fn peek_token(&mut self) -> S<T<'a>> {
|
||||
self.peek_token_optional()
|
||||
.unwrap_or(S(T::LineEnd, self.ctx.eof()))
|
||||
}
|
||||
|
||||
fn expect_token(&mut self, expected: T<'a>) -> (bool, Span) {
|
||||
match self.peek_token() {
|
||||
S(token, span) if token == expected => {
|
||||
self.next_token();
|
||||
(true, span)
|
||||
}
|
||||
} else {
|
||||
self.logs.emit_error(
|
||||
format!("unexpected eof expected {:#}", expected),
|
||||
self.eof(),
|
||||
);
|
||||
(false, self.eof())
|
||||
S(token, span) => {
|
||||
self.ctx.emit_error(
|
||||
format!("unexpected {:#} expected {:}", token, expected),
|
||||
span,
|
||||
);
|
||||
(false, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_symbol(&mut self) -> Spanned<Symbol<'a>> {
|
||||
match self.next_token() {
|
||||
Some(Spanned(Token::Tilde, r)) => Spanned(Symbol::Epsilon, r),
|
||||
Some(Spanned(Token::Ident("epsilon"), r)) => Spanned(Symbol::Epsilon, r),
|
||||
Some(Spanned(Token::Ident(super::EPSILON_LOWER), r)) => Spanned(Symbol::Epsilon, r),
|
||||
Some(Spanned(Token::Ident(ident), r)) => Spanned(Symbol::Ident(ident), r),
|
||||
Some(Spanned(got, span)) => {
|
||||
self.logs.emit_error(
|
||||
fn parse_as_symbol(&mut self, tok: S<T<'a>>) -> S<Symbol<'a>> {
|
||||
match tok {
|
||||
S(T::Tilde, r) => S(Symbol::Epsilon, r),
|
||||
S(T::Ident("epsilon"), r) => S(Symbol::Epsilon, r),
|
||||
S(T::Ident(super::EPSILON_LOWER), r) => S(Symbol::Epsilon, r),
|
||||
S(T::Ident(ident), r) => S(Symbol::Ident(ident), r),
|
||||
S(got, span) => {
|
||||
self.ctx.emit_error(
|
||||
format!(
|
||||
"unexpected {:#}, expected {:} | {:} (symbol)",
|
||||
"unexpected {:#} expected symbol ( {:} | {:} )",
|
||||
got,
|
||||
Token::Tilde,
|
||||
Token::Ident("")
|
||||
T::Tilde,
|
||||
T::Ident("")
|
||||
),
|
||||
span,
|
||||
);
|
||||
Spanned(Symbol::Ident("<INVALID>"), span)
|
||||
}
|
||||
None => {
|
||||
self.logs.emit_error(
|
||||
format!(
|
||||
"unexpected eof expected {:} | {:} (symbol)",
|
||||
Token::Tilde,
|
||||
Token::Ident("")
|
||||
),
|
||||
self.eof(),
|
||||
);
|
||||
Spanned(Symbol::Ident("<INVALID>"), self.eof())
|
||||
S(Symbol::Ident("<INVALID>"), span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_tupple(&mut self) -> Spanned<Tuple<'a>> {
|
||||
fn parse_symbol(&mut self) -> S<Symbol<'a>> {
|
||||
let next = self.next_token();
|
||||
self.parse_as_symbol(next)
|
||||
}
|
||||
|
||||
fn parse_tupple(&mut self) -> S<Tuple<'a>> {
|
||||
let mut items = Vec::new();
|
||||
let (matched, start) = self.expect_token(Token::LPar);
|
||||
let (matched, start) = self.expect_token(T::LPar);
|
||||
if !matched {
|
||||
return Spanned(Tuple(Vec::new()), start);
|
||||
return S(Tuple(Vec::new()), start);
|
||||
}
|
||||
|
||||
while !matches!(self.peek_token(), Some(Spanned(Token::RPar, _))) {
|
||||
while !matches!(self.peek_token().0, T::RPar) {
|
||||
items.push(self.parse_item());
|
||||
if matches!(self.peek_token(), Some(Spanned(Token::Comma, _))) {
|
||||
if matches!(self.peek_token().0, T::Comma) {
|
||||
self.next_token();
|
||||
}
|
||||
match self.peek_token() {
|
||||
None => {
|
||||
self.logs.emit_error(
|
||||
format!("unexpected eof expected {:}", Token::RPar),
|
||||
self.eof(),
|
||||
);
|
||||
return Spanned(Tuple(items), start.join(self.eof()));
|
||||
}
|
||||
Some(Spanned(Token::LineEnd, span)) => {
|
||||
self.logs
|
||||
.emit_error(format!("unexpected eol expected {:}", Token::RPar), span);
|
||||
return Spanned(Tuple(items), start.join(span));
|
||||
}
|
||||
_ => {}
|
||||
if let S(T::LineEnd, span) = self.peek_token() {
|
||||
self.ctx
|
||||
.emit_error(format!("unexpected eol expected {:}", T::RPar), span);
|
||||
return S(Tuple(items), start.join(span));
|
||||
}
|
||||
}
|
||||
|
||||
let (_, end) = self.expect_token(Token::RPar);
|
||||
let (_, end) = self.expect_token(T::RPar);
|
||||
|
||||
Spanned(Tuple(items), start.join(end))
|
||||
S(Tuple(items), start.join(end))
|
||||
}
|
||||
|
||||
fn parse_item(&mut self) -> Spanned<Item<'a>> {
|
||||
match self.peek_token() {
|
||||
Some(Spanned(Token::Ident(_) | Token::Tilde, _)) => {
|
||||
self.parse_symbol().map(Item::Symbol)
|
||||
}
|
||||
Some(Spanned(Token::LPar, _)) => self.parse_tupple().map(Item::Tuple),
|
||||
Some(Spanned(Token::LBrace | Token::LBracket, _)) => self.parse_list().map(Item::List),
|
||||
Some(Spanned(got, span)) => {
|
||||
self.next_token();
|
||||
self.logs.emit_error(
|
||||
fn parse_item(&mut self) -> S<Item<'a>> {
|
||||
match self.peek_token().0 {
|
||||
T::Ident(_) | T::Tilde => self.parse_symbol().map(Item::Symbol),
|
||||
T::LPar => self.parse_tupple().map(Item::Tuple),
|
||||
T::LBrace | T::LBracket => self.parse_list().map(Item::List),
|
||||
_ => {
|
||||
let S(got, span) = self.next_token();
|
||||
self.ctx.emit_error(
|
||||
format!(
|
||||
"unexpected {:#}, expected {:} | {:} | {:} | {:} | {:} (item)",
|
||||
"unexpected {:#} expected item ( {:} | {:} | {:} | {:} | {:} )",
|
||||
got,
|
||||
Token::Tilde,
|
||||
Token::Ident(""),
|
||||
Token::LPar,
|
||||
Token::LBrace,
|
||||
Token::LBracket,
|
||||
T::Tilde,
|
||||
T::Ident(""),
|
||||
T::LPar,
|
||||
T::LBrace,
|
||||
T::LBracket,
|
||||
),
|
||||
span,
|
||||
);
|
||||
Spanned(Item::Symbol(Symbol::Ident("<INVALID>")), span)
|
||||
}
|
||||
None => {
|
||||
self.logs.emit_error(
|
||||
format!(
|
||||
"unexpected eof expected {:} | {:} | {:} | {:} | {:} (item)",
|
||||
Token::Tilde,
|
||||
Token::Ident(""),
|
||||
Token::LPar,
|
||||
Token::LBrace,
|
||||
Token::LBracket,
|
||||
),
|
||||
self.eof(),
|
||||
);
|
||||
Spanned(Item::Symbol(Symbol::Ident("<INVALID>")), self.eof())
|
||||
S(Item::Symbol(Symbol::Ident("<INVALID>")), span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_list(&mut self) -> Spanned<List<'a>> {
|
||||
fn parse_list(&mut self) -> S<List<'a>> {
|
||||
let mut list = Vec::new();
|
||||
|
||||
let (start, match_end) = match self.next_token() {
|
||||
Some(Spanned(Token::LBrace, r)) => (r, Token::RBrace),
|
||||
Some(Spanned(Token::LBracket, r)) => (r, Token::RBracket),
|
||||
Some(Spanned(got, span)) => {
|
||||
self.logs.emit_error(
|
||||
S(T::LBrace, span) => (span, T::RBrace),
|
||||
S(T::LBracket, span) => (span, T::RBracket),
|
||||
S(got, span) => {
|
||||
self.ctx.emit_error(
|
||||
format!(
|
||||
"unexpected {:#}, expected {:} | {:}",
|
||||
"unexpected {:#} expected list start ( {:} | {:} )",
|
||||
got,
|
||||
Token::RBrace,
|
||||
Token::RBracket
|
||||
T::RBrace,
|
||||
T::RBracket
|
||||
),
|
||||
span,
|
||||
);
|
||||
return Spanned(List(Vec::new(), ListKind::BracketComma), span);
|
||||
}
|
||||
None => {
|
||||
self.logs.emit_error(
|
||||
format!(
|
||||
"unexpected eof expected {:} | {:}",
|
||||
Token::RBrace,
|
||||
Token::RBracket
|
||||
),
|
||||
self.eof(),
|
||||
);
|
||||
return Spanned(List(Vec::new(), ListKind::BracketComma), self.eof());
|
||||
return S(List(Vec::new(), ListKind::BracketComma), span);
|
||||
}
|
||||
};
|
||||
|
||||
let mut comma = false;
|
||||
while self.peek_token().map(|t| t.0) != Some(match_end) {
|
||||
while self.peek_token().0 != match_end {
|
||||
list.push(self.parse_item());
|
||||
if matches!(self.peek_token(), Some(Spanned(Token::Comma, _))) {
|
||||
|
||||
if list.len() != 1
|
||||
&& self.peek_token().0 != match_end
|
||||
&& !matches!(self.peek_token().0, T::LineEnd)
|
||||
&& matches!(self.peek_token().0, T::Comma) != comma
|
||||
{
|
||||
let span = self.peek_token().1;
|
||||
self.ctx.emit_warning(
|
||||
"inconsistent comma delimiting. use commas to delimit all or no items",
|
||||
span,
|
||||
);
|
||||
}
|
||||
if matches!(self.peek_token().0, T::Comma) {
|
||||
comma = true;
|
||||
self.next_token();
|
||||
}
|
||||
match self.peek_token() {
|
||||
None => {
|
||||
self.logs.emit_error(
|
||||
format!("unexpected eof expected {:}", match_end),
|
||||
self.eof(),
|
||||
);
|
||||
return Spanned(List(list, ListKind::BraceComma), start.join(self.eof()));
|
||||
}
|
||||
Some(Spanned(Token::LineEnd, span)) => {
|
||||
self.logs
|
||||
.emit_error(format!("unexpected eol expected {:}", match_end), span);
|
||||
return Spanned(List(list, ListKind::BraceComma), start.join(span));
|
||||
}
|
||||
_ => {}
|
||||
if let S(T::LineEnd, span) = self.peek_token() {
|
||||
self.ctx.emit_error(
|
||||
format!("unexpected eol expected list close ( {:} )", match_end),
|
||||
span,
|
||||
);
|
||||
return S(List(list, ListKind::BraceComma), start.join(span));
|
||||
}
|
||||
}
|
||||
let (_, end) = self.expect_token(match_end);
|
||||
let kind = match (comma, match_end) {
|
||||
(true, Token::RBrace) => ListKind::BraceComma,
|
||||
(false, Token::RBrace) => ListKind::Brace,
|
||||
(true, Token::RBracket) => ListKind::BracketComma,
|
||||
(false, Token::RBracket) => ListKind::Bracket,
|
||||
(true, T::RBrace) => ListKind::BraceComma,
|
||||
(false, T::RBrace) => ListKind::Brace,
|
||||
(true, T::RBracket) => ListKind::BracketComma,
|
||||
(false, T::RBracket) => ListKind::Bracket,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Spanned(List(list, kind), start.join(end))
|
||||
S(List(list, kind), start.join(end))
|
||||
}
|
||||
|
||||
fn parse_regex(&mut self) -> Spanned<Regex<'a>> {
|
||||
fn parse_regex(&mut self) -> S<Regex<'a>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse_production_rule(
|
||||
&mut self,
|
||||
sym: Symbol<'a>,
|
||||
start: Span,
|
||||
) -> Option<Spanned<TopLevel<'a>>> {
|
||||
let mut lhs_group = ProductionGroup(vec![Spanned(sym, start)]);
|
||||
fn parse_production_rule(&mut self, S(sym, start): S<Symbol<'a>>) -> Option<S<TopLevel<'a>>> {
|
||||
let mut lhs_group = ProductionGroup(vec![S(sym, start)]);
|
||||
let mut lhs_group_end = start;
|
||||
while !matches!(
|
||||
self.peek_token(),
|
||||
None | Some(Spanned(Token::LSmallArrow | Token::LineEnd, _))
|
||||
) {
|
||||
while !matches!(self.peek_token().0, T::LSmallArrow | T::LineEnd) {
|
||||
let sym = self.parse_symbol();
|
||||
lhs_group_end = sym.1;
|
||||
lhs_group.0.push(sym);
|
||||
}
|
||||
if !self.expect_token(Token::LSmallArrow).0 {
|
||||
return Some(Spanned(
|
||||
if !self.expect_token(T::LSmallArrow).0 {
|
||||
return Some(S(
|
||||
TopLevel::ProductionRule(
|
||||
Spanned(lhs_group, start.join(lhs_group_end)),
|
||||
Spanned(vec![], lhs_group_end),
|
||||
S(lhs_group, start.join(lhs_group_end)),
|
||||
S(vec![], lhs_group_end),
|
||||
),
|
||||
start.join(lhs_group_end),
|
||||
));
|
||||
|
|
@ -287,25 +246,21 @@ impl<'a> Parser<'a> {
|
|||
|
||||
loop {
|
||||
let mut group = ProductionGroup(vec![]);
|
||||
while !matches!(
|
||||
self.peek_token(),
|
||||
None | Some(Spanned(Token::LineEnd | Token::Or, _))
|
||||
) {
|
||||
while !matches!(self.peek_token().0, T::LineEnd | T::Or) {
|
||||
group.0.push(self.parse_symbol());
|
||||
}
|
||||
|
||||
if group.0.is_empty() {
|
||||
let eof = self.eof();
|
||||
let span = self.peek_token().map(|t| t.1).unwrap_or(eof);
|
||||
self.logs
|
||||
let span = self.peek_token().1;
|
||||
self.ctx
|
||||
.emit_error("cannot have empty production group", span);
|
||||
}
|
||||
|
||||
let group_start = group.0.first().map(|g| g.1).unwrap_or(start);
|
||||
let group_end = group.0.last().map(|g| g.1).unwrap_or(start);
|
||||
groups.push(Spanned(group, group_start.join(group_end)));
|
||||
groups.push(S(group, group_start.join(group_end)));
|
||||
|
||||
if matches!(self.peek_token(), Some(Spanned(Token::Or, _))) {
|
||||
if matches!(self.peek_token().0, T::Or) {
|
||||
self.next_token();
|
||||
} else {
|
||||
break;
|
||||
|
|
@ -313,7 +268,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
if groups.is_empty() {
|
||||
self.logs.emit_error(
|
||||
self.ctx.emit_error(
|
||||
"cannot have empty production rule",
|
||||
start.join(lhs_group_end),
|
||||
);
|
||||
|
|
@ -322,10 +277,10 @@ impl<'a> Parser<'a> {
|
|||
let rules_start = groups.first().map(|f| f.1).unwrap_or(start);
|
||||
let rules_end = groups.last().map(|f| f.1).unwrap_or(start);
|
||||
|
||||
Some(Spanned(
|
||||
Some(S(
|
||||
TopLevel::ProductionRule(
|
||||
Spanned(lhs_group, start.join(lhs_group_end)),
|
||||
Spanned(groups, rules_start.join(rules_end)),
|
||||
S(lhs_group, start.join(lhs_group_end)),
|
||||
S(groups, rules_start.join(rules_end)),
|
||||
),
|
||||
start.join(rules_end),
|
||||
))
|
||||
|
|
@ -335,106 +290,73 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
ident: &'a str,
|
||||
start: Span,
|
||||
) -> Option<Spanned<TopLevel<'a>>> {
|
||||
) -> Option<S<TopLevel<'a>>> {
|
||||
let tuple = self.parse_tupple();
|
||||
let span = start.join(tuple.1);
|
||||
let dest = Spanned((Spanned(ident, start), tuple), span);
|
||||
if !self.expect_token(Token::Eq).0 {
|
||||
let dest = S((S(ident, start), tuple), span);
|
||||
if !self.expect_token(T::Eq).0 {
|
||||
return None;
|
||||
}
|
||||
let item = self.parse_item();
|
||||
let span = start.join(item.1);
|
||||
Some(Spanned(TopLevel::TransitionFunc(dest, item), span))
|
||||
Some(S(TopLevel::TransitionFunc(dest, item), span))
|
||||
}
|
||||
|
||||
pub fn next_element(&mut self) -> Option<Spanned<TopLevel<'a>>> {
|
||||
pub fn next_element(&mut self) -> Option<S<TopLevel<'a>>> {
|
||||
let result = loop {
|
||||
let next = self.next_token()?;
|
||||
let next = self.next_token_optional()?;
|
||||
match (next, self.peek_token()) {
|
||||
(Spanned(Token::LineEnd, _), _) => self.advance_line(),
|
||||
(Spanned(Token::Ident(ident), start), Some(Spanned(Token::LPar, _))) => {
|
||||
// empty
|
||||
(S(T::LineEnd, _), _) => self.advance_line(),
|
||||
// transition function
|
||||
(S(T::Ident(ident), start), S(T::LPar, _)) => {
|
||||
if let Some(tf) = self.parse_transition_function(ident, start) {
|
||||
break Some(tf);
|
||||
}
|
||||
}
|
||||
(
|
||||
Spanned(
|
||||
Token::Ident(EPSILON_LOWER) | Token::Ident("epsilon") | Token::Tilde,
|
||||
start,
|
||||
),
|
||||
Some(Spanned(Token::LSmallArrow | Token::Ident(_) | Token::Tilde, _)),
|
||||
) => {
|
||||
if let Some(pr) = self.parse_production_rule(Symbol::Epsilon, start) {
|
||||
break Some(pr);
|
||||
}
|
||||
}
|
||||
(
|
||||
Spanned(Token::Ident(ident), start),
|
||||
Some(Spanned(Token::LSmallArrow | Token::Ident(_) | Token::Tilde, _)),
|
||||
) => {
|
||||
if let Some(pr) = self.parse_production_rule(Symbol::Ident(ident), start) {
|
||||
break Some(pr);
|
||||
}
|
||||
}
|
||||
(Spanned(Token::Ident(ident), start), Some(Spanned(Token::Eq, _))) => {
|
||||
let name = Spanned(ident, start);
|
||||
if !self.expect_token(Token::Eq).0 {
|
||||
// item
|
||||
(S(T::Ident(ident), start), S(T::Eq, _)) => {
|
||||
let name = S(ident, start);
|
||||
if !self.expect_token(T::Eq).0 {
|
||||
continue;
|
||||
}
|
||||
let item = self.parse_item();
|
||||
let span = start.join(item.1);
|
||||
break Some(Spanned(TopLevel::Item(name, item), span));
|
||||
break Some(S(TopLevel::Item(name, item), span));
|
||||
}
|
||||
(Spanned(Token::Ident(_), _), after) => {
|
||||
match after {
|
||||
Some(Spanned(tok, span)) => {
|
||||
self.logs.emit_error(
|
||||
format!(
|
||||
"unexpected {:#}, expected {:} | {:}",
|
||||
tok,
|
||||
Token::Eq,
|
||||
Token::LSmallArrow
|
||||
),
|
||||
span,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
self.logs.emit_error(
|
||||
format!(
|
||||
"unexpected eof, expected {:} | {:}",
|
||||
Token::Eq,
|
||||
Token::LSmallArrow
|
||||
),
|
||||
self.eof(),
|
||||
);
|
||||
}
|
||||
// production rule
|
||||
(
|
||||
sym @ S(T::Ident(_) | T::Tilde, _),
|
||||
S(T::LSmallArrow | T::Ident(_) | T::Tilde, _),
|
||||
) => {
|
||||
let sym = self.parse_as_symbol(sym);
|
||||
if let Some(pr) = self.parse_production_rule(sym) {
|
||||
break Some(pr);
|
||||
}
|
||||
while !matches!(self.next_token(), None | Some(Spanned(Token::LineEnd, _))) {}
|
||||
}
|
||||
|
||||
(S(T::Ident(_), _), S(tok, span)) => {
|
||||
self.ctx.emit_error(
|
||||
format!(
|
||||
"unexpected {:#} expected {:} | {:}",
|
||||
tok,
|
||||
T::Eq,
|
||||
T::LSmallArrow
|
||||
),
|
||||
span,
|
||||
);
|
||||
while !matches!(self.next_token().0, T::LineEnd) {}
|
||||
}
|
||||
_ => {
|
||||
self.logs.emit_error(
|
||||
format!("unexpected {:#}, expected {:}", next.0, Token::Ident("")),
|
||||
self.ctx.emit_error(
|
||||
format!("unexpected {:#} expected {:}", next.0, T::Ident("")),
|
||||
next.1,
|
||||
);
|
||||
while !matches!(self.next_token(), None | Some(Spanned(Token::LineEnd, _))) {}
|
||||
while !matches!(self.next_token().0, T::LineEnd) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
self.advance_line();
|
||||
result
|
||||
}
|
||||
|
||||
pub fn parse_elements(mut self) -> (Vec<Spanned<TopLevel<'a>>>, Logs<'a>) {
|
||||
let mut result = Vec::new();
|
||||
|
||||
while let Some(next) = self.next_element() {
|
||||
result.push(next)
|
||||
}
|
||||
|
||||
(result, self.logs)
|
||||
}
|
||||
|
||||
pub fn logs(&self) -> impl Iterator<Item = LogEntryDisplay<'_>> {
|
||||
self.logs.displayable()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28
src/main.rs
28
src/main.rs
|
|
@ -1,26 +1,24 @@
|
|||
use automata::automata::npda;
|
||||
use automata::{automata::npda, loader::Context};
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("../example.npda");
|
||||
let mut ctx = Context::new(input);
|
||||
|
||||
let table = match npda::TransitionTable::load_table(input) {
|
||||
Ok((ok, logs)) => {
|
||||
for log in logs.displayable() {
|
||||
println!("{log}")
|
||||
}
|
||||
ok
|
||||
}
|
||||
Err(logs) => {
|
||||
for log in logs.displayable() {
|
||||
println!("{log}")
|
||||
}
|
||||
return;
|
||||
}
|
||||
let machine = automata::loader::parse_universal(&mut ctx);
|
||||
for log in ctx.logs_display(){
|
||||
println!("{log}")
|
||||
}
|
||||
|
||||
let machine = match machine{
|
||||
Some(automata::loader::Machine::Npda(npda)) => {
|
||||
npda
|
||||
},
|
||||
None => return,
|
||||
};
|
||||
|
||||
let input = "aababaaba";
|
||||
println!("running on: '{input}'");
|
||||
let mut simulator = npda::Simulator::begin(input, table);
|
||||
let mut simulator = npda::Simulator::begin(input, machine);
|
||||
loop {
|
||||
match simulator.step() {
|
||||
npda::SimulatorResult::Pending => {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue