diff --git a/automata/src/automatan/pda.rs b/automata/src/automatan/pda.rs index 5532a14..80f82d7 100644 --- a/automata/src/automatan/pda.rs +++ b/automata/src/automatan/pda.rs @@ -2,51 +2,60 @@ use std::collections::HashSet; use super::*; -use crate::{delta_lower, gamma_upper, loader::{ +use crate::{delta_lower, dual_struct_serde, gamma_upper, loader::{ Context, INITIAL_STACK, INITIAL_STATE, Spanned, ast::{self, Symbol as Sym}, log::LogSink }, sigma_upper}; -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct TransitionFrom<'a> { - pub state: State<'a>, - pub letter: Option>, - pub symbol: Symbol<'a>, +dual_struct_serde! { + #[derive(Debug, PartialEq, Eq, Clone, Hash)] + pub struct TransitionFrom<'a> { + #[serde(borrow)] + pub state: State<'a>, + #[serde(borrow)] + pub letter: Option>, + #[serde(borrow)] + pub symbol: Symbol<'a>, + } } -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct TransitionTo<'a> { - pub state: State<'a>, - pub stack: Vec>, +dual_struct_serde! { + #[derive(Debug, PartialEq, Eq, Clone, Hash)] + pub struct TransitionTo<'a> { + #[serde(borrow)] + pub state: State<'a>, + #[serde(borrow)] + pub stack: Vec>, - pub transition: Span, - pub function: Span, + pub transition: Span, + pub function: Span, + } } -#[derive(Clone, Debug)] -#[allow(unused)] -#[cfg_attr(feature = "serde", serde_with::serde_as)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct Pda<'a> { - pub initial_state: State<'a>, - pub initial_stack: Symbol<'a>, - pub states: HashMap, StateInfo>, - pub symbols: HashMap, SymbolInfo>, - pub alphabet: HashMap, LetterInfo>, +dual_struct_serde! { {#[serde_with::serde_as]} + #[derive(Clone, Debug)] + pub struct Pda<'a> { + #[serde(borrow)] + pub initial_state: State<'a>, + #[serde(borrow)] + pub initial_stack: Symbol<'a>, + #[serde(borrow)] + pub states: HashMap, StateInfo>, + #[serde(borrow)] + pub symbols: HashMap, SymbolInfo>, + #[serde(borrow)] + pub alphabet: HashMap, LetterInfo>, - pub final_states: Option, StateInfo>>, + #[serde(borrow)] + pub final_states: Option, StateInfo>>, - #[cfg(feature = "serde")] - #[serde_as(as = "serde_with::Seq<(_, _)>")] - pub transitions: HashMap, HashSet>>, - - #[cfg(not(feature = "serde"))] - pub transitions: HashMap, HashSet>>, + #[serde(borrow)] + #[serde_as(as = "serde_with::Seq<(_, _)>")] + pub transitions: HashMap, HashSet>>, + } } impl<'a> Pda<'a> { - pub fn parse( + pub fn compile( items: impl Iterator>>, ctx: &mut Context<'a>, options: Options, diff --git a/automata/src/automatan/tm.rs b/automata/src/automatan/tm.rs index 179ab45..7c52244 100644 --- a/automata/src/automatan/tm.rs +++ b/automata/src/automatan/tm.rs @@ -2,57 +2,65 @@ use std::collections::HashSet; use super::*; -use crate::{delta_lower, gamma_upper, loader::{ +use crate::{delta_lower, dual_struct_serde, gamma_upper, loader::{ BLANK_SYMBOL, Context, Spanned, ast::{self, Symbol as Sym}, log::LogSink }}; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct TransitionFrom<'a> { - pub state: State<'a>, - pub symbol: Symbol<'a>, +dual_struct_serde! { + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] + pub struct TransitionFrom<'a> { + #[serde(borrow)] + pub state: State<'a>, + #[serde(borrow)] + pub symbol: Symbol<'a>, + } } -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Direction { Left, Right, None, } -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct TransitionTo<'a> { - pub state: State<'a>, - pub symbol: Symbol<'a>, - pub direction: Direction, +dual_struct_serde! { + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] + pub struct TransitionTo<'a> { + #[serde(borrow)] + pub state: State<'a>, + #[serde(borrow)] + pub symbol: Symbol<'a>, + pub direction: Direction, - pub transition: Span, - pub function: Span, + pub transition: Span, + pub function: Span, + } } -#[derive(Clone, Debug)] -#[allow(unused)] -#[cfg_attr(feature = "serde", serde_with::serde_as)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -pub struct Tm<'a> { - pub initial_state: State<'a>, - pub initial_tape: Symbol<'a>, - pub states: HashMap, StateInfo>, - pub symbols: HashMap, SymbolInfo>, +dual_struct_serde! {{#[serde_with::serde_as]} + #[derive(Clone, Debug)] + pub struct Tm<'a> { + #[serde(borrow)] + pub initial_state: State<'a>, + #[serde(borrow)] + pub initial_tape: Symbol<'a>, + #[serde(borrow)] + pub states: HashMap, StateInfo>, + #[serde(borrow)] + pub symbols: HashMap, SymbolInfo>, - pub final_states: HashMap, StateInfo>, + #[serde(borrow)] + pub final_states: HashMap, StateInfo>, - #[cfg(feature = "serde")] - #[serde_as(as = "serde_with::Seq<(_, _)>")] - pub transitions: HashMap, HashSet>>, - #[cfg(not(feature = "serde"))] - pub transitions: HashMap, HashSet>>, + + #[serde(borrow)] + #[serde_as(as = "serde_with::Seq<(_, _)>")] + pub transitions: HashMap, HashSet>>, + } } impl<'a> Tm<'a> { - pub fn parse( + pub fn compile( items: impl Iterator>>, ctx: &mut Context<'a>, options: Options, diff --git a/automata/src/lib.rs b/automata/src/lib.rs index ecad2bb..f1b2f24 100644 --- a/automata/src/lib.rs +++ b/automata/src/lib.rs @@ -1,7 +1,6 @@ pub mod automatan; pub mod loader; - #[macro_export] macro_rules! dual_struct_serde { ($({$(#[$serde_specific:meta])*})? @@ -33,4 +32,83 @@ macro_rules! dual_struct_serde { ),* } }; -} \ No newline at end of file +} + +#[macro_export] +macro_rules! dual_enum_serde { + ( + $( {$(#[$serde_specific:meta])*} )? + $(#[$enum_meta:meta])* + $vis:vis enum $Name:ident $(<$($gen:tt),*>)? + { + $( + $(#[$variant_meta:meta])* + $Variant:ident + $( + // Tuple variant: Variant(T1, T2, ...) + ( $( + $(#[$tfield_meta:meta])* + $tfield_ty:ty + ),* $(,)? ) + )? + $( + // Struct variant: Variant { a: T, b: U, ... } + { $( + $(#[$sfield_meta:meta])* + $sfield_vis:vis $sfield_name:ident : $sfield_ty:ty + ),* $(,)? } + )? + ),* $(,)? + } + ) => { + #[cfg(feature = "serde")] + $(#[$enum_meta])* + #[derive(serde::Serialize, serde::Deserialize)] + $( $(#[$serde_specific])* )? + $vis enum $Name $(<$($gen),*>)? { + $( + $(#[$variant_meta])* + $Variant + $( + ( + $( + $(#[$tfield_meta])* + $tfield_ty + ),* + ) + )? + $( + { + $( + $(#[$sfield_meta])* + $sfield_vis $sfield_name: $sfield_ty + ),* + } + )? + ),* + } + + #[cfg(not(feature = "serde"))] + $(#[$enum_meta])* + $vis enum $Name $(<$($gen),*>)? { + $( + // strip variant + field attrs in non-serde version + $Variant + $( + ( + $( + $tfield_ty + ),* + ) + )? + $( + { + $( + $sfield_vis $sfield_name: $sfield_ty + ),* + } + )? + ),* + } + }; +} diff --git a/automata/src/loader/mod.rs b/automata/src/loader/mod.rs index 5379a3d..ef4546b 100644 --- a/automata/src/loader/mod.rs +++ b/automata/src/loader/mod.rs @@ -1,9 +1,8 @@ use crate::{ - automatan::*, - loader::{ + automatan::*, dual_enum_serde, dual_struct_serde, loader::{ ast::TopLevel, log::{LogEntry, LogSink}, - }, + } }; pub mod ast; @@ -120,13 +119,14 @@ impl<'a> Context<'a> { } } -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -#[cfg_attr(feature = "serde", serde(tag = "type"))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -pub enum Machine<'a> { - Fa(fa::Fa<'a>), - Pda(pda::Pda<'a>), - Tm(tm::Tm<'a>), +dual_enum_serde!{ + {#[serde(tag = "type")] #[serde(rename_all = "snake_case")]} + #[derive(Clone, Debug)] + pub enum Machine<'a> { + Fa(#[serde(borrow)] fa::Fa<'a>), + Pda(#[serde(borrow)] pda::Pda<'a>), + Tm(#[serde(borrow)] tm::Tm<'a>), + } } pub fn parse_universal<'a>(ctx: &mut Context<'a>) -> Option> { @@ -194,9 +194,9 @@ pub fn parse_universal<'a>(ctx: &mut Context<'a>) -> Option> { Some(match parse_type(items.next(), ctx)? { Type::Dfa => Machine::Fa(fa::Fa::compile(items, ctx, D)?), Type::Nfa => Machine::Fa(fa::Fa::compile(items, ctx, N)?), - Type::Dpda => Machine::Pda(pda::Pda::parse(items, ctx, D)?), - Type::Npda => Machine::Pda(pda::Pda::parse(items, ctx, N)?), - Type::Tm => Machine::Tm(tm::Tm::parse(items, ctx, D)?), - Type::Ntm => Machine::Tm(tm::Tm::parse(items, ctx, N)?), + Type::Dpda => Machine::Pda(pda::Pda::compile(items, ctx, D)?), + Type::Npda => Machine::Pda(pda::Pda::compile(items, ctx, N)?), + Type::Tm => Machine::Tm(tm::Tm::compile(items, ctx, D)?), + Type::Ntm => Machine::Tm(tm::Tm::compile(items, ctx, N)?), }) }