parser-pda 0.1.6

Example of a simple parser pushdown automaton implementation
Documentation

use crate::defs::{ SegmentDelimSyms::*, SegmentTypes, 
    ParserCtx, PDAStackCtx, ParsedSegment };

fsm!( ParserNonDetPDA<ParserCtx, PDAStackCtx> [
    Idle on Start          
        => NewSentence on LeftBracket  => PlainSegment,
    
    NewSentence on RightBracket => InvalidSegment,
    NewSentence on Letter(char) 
        => PlainSegment on LeftBracket 
        => PlainSegment on RightBracket => ?,

    PlainSegment on EndOfSentence => NewSentence,   
    _ on EndOfSentence => NewSentence,
    _ on EndOfInput => Idle,
    ],
    [
        Idle entry, NewSentence exit
    ]
);

on_state_handler!( Idle entry for ParserNonDetPDA {
    data.index = 0;
});
on_state_handler!( NewSentence exit for ParserNonDetPDA {
    stack.push(PDAStackCtx { sym: SentenceStart, seg_start: data.index} );
});
    
transition_handler!( Idle on Start for ParserNonDetPDA {
});

transition_handler!( NewSentence on Letter(char) for ParserNonDetPDA {
});

transition_handler!( NewSentence on LeftBracket for ParserNonDetPDA {
    stack.push(PDAStackCtx { sym: Bracket, seg_start: data.index } );
});

transition_handler!( NewSentence on RightBracket for ParserNonDetPDA {
});


transition_handler!( PlainSegment on LeftBracket for ParserNonDetPDA {
    let top = stack.last().unwrap();
    if top.sym == SegmentStart || top.sym == SentenceStart {
        data.segments.push(ParsedSegment { 
            tp: SegmentTypes::Plain, 
            seg: (top.seg_start, data.index),
            rank: stack.len(), 
        });
    }
    stack.push(PDAStackCtx { sym: Bracket, seg_start: data.index} );
});

conditional_handler!(PlainSegment on RightBracket for ParserNonDetPDA {
    if &Bracket == stack.last().unwrap() {
        let top = stack.pop().unwrap();
        data.segments.push(ParsedSegment { 
            tp: SegmentTypes::Bracketed, 
            seg: (top.seg_start + 1, data.index),
            rank: stack.len(), 
        });
        PlainSegment            
    } else {
        let top = stack.last().unwrap();
        data.segments.push(ParsedSegment { 
            tp: SegmentTypes::Plain, 
            seg: (top.seg_start, data.index),
            rank: stack.len(),
        });
        stack.push(PDAStackCtx { sym: SegmentStart, seg_start: data.index } );
        InvalidSegment                
    }
});

transition_handler!(PlainSegment on EndOfSentence for ParserNonDetPDA {
    if let Some(_) = stack.last() {
        let top = stack.pop().unwrap();
        let tp = if SentenceStart == top {
            SegmentTypes::Sentence
        } else if SegmentStart == top {
            SegmentTypes::Plain
        } else { unimplemented!(); };
        data.segments.push(ParsedSegment { 
            tp, 
            seg: (top.seg_start, data.index),
            rank: stack.len(),
        });        
    }
});

transition_handler!(_ on EndOfSentence for ParserNonDetPDA {
    Self::drain_unbalanced(data, stack);
});

transition_handler!( _ on EndOfInput for ParserNonDetPDA {
    if let Some(top) = stack.last() {
        if &SentenceStart == top {
            data.segments.push(ParsedSegment { 
                tp: SegmentTypes::Tail, 
                seg: (stack.pop().unwrap().seg_start, data.index),
                rank: stack.len(),
            });
        } else {
            Self::drain_unbalanced(data, stack);
        }
    }
});

transition_handler!( NewSentence on EndOfSentence for ParserNonDetPDA {
});

impl ParserNonDetPDA {
    pub fn start(&mut self) {
        self.signal(&Start);
    }
    pub fn next(&mut self, signal: &ParserNonDetPDASignals) {
        self.signal(signal);
        self.data.index += 1;
    }
    pub fn stop(&mut self) {
        self.signal(&EndOfInput);
    }

    fn drain_unbalanced(
        data: &mut <Self as ParserNonDetPDATrait>::DataItem, 
        stack: &mut Vec<<Self as ParserNonDetPDATrait>::StackSymbolItem>,
    ) {
        while let Some(top) = stack.pop() {
            let tp = 
                if Bracket == top {  SegmentTypes::UnbalancedLeftBracket } 
                else if SegmentStart == top { SegmentTypes::UnbalancedRightSth}
                else if SentenceStart == top { SegmentTypes::InvalidSentence}
                else {
                    unimplemented!();
                };
            data.segments.push(ParsedSegment { 
                tp, 
                seg: (top.seg_start, data.index),
                rank: stack.len(),
            });
        }
    }
}