Skip to content
Snippets Groups Projects
main.rs 5.53 KiB
mod parser;

use std::marker::PhantomData;

use parser::{Parser};


mod combinators;
use combinators::non_primitive_combinators::ThenR;
use combinators::primitive_combinators::Alternative;

use crate::combinators::common::characters::Char;

#[macro_use]
mod preprocessor;

/* Operators
infixr 3 <|>
infixl 4 <*>
infixl 4 <*
infixl 4 *>
infixl 4 <~>
*/

#[macro_use]
macro_rules! infix {
    // done converting
    (@cvt () $postfix:tt) => { infix!(@pfx () $postfix) };
    //                                |    |  ^ postfix expression
    //                                |    ^ operand stack
    //                                ^ postfix interpreter
    
    // infix to postfix conversion using the rules at the bottom of this page: http://csis.pace.edu/~wolf/CS122/infix-postfix.htm
    
    // at end of input, flush the operators to postfix
    (@cvt ($ophead:tt $($optail:tt)*) ($($postfix:tt)*)) => { infix!(@cvt ($($optail)*) ($($postfix)* $ophead)) };
    
    // 2. push an operator onto the stack if it's empty or has a left-paren on top
    (@cvt (                 ) $postfix:tt <|> $($tail:tt)*) => { infix!(@cvt (<|>               ) $postfix $($tail)*) };

    (@cvt (                 ) $postfix:tt *> $($tail:tt)*) => { infix!(@cvt (*>               ) $postfix $($tail)*) };
    //(@cvt (                 ) $postfix:tt / $($tail:tt)*) => { infix!(@cvt (/               ) $postfix $($tail)*) };
    (@cvt (LP $($optail:tt)*) $postfix:tt <|> $($tail:tt)*) => { infix!(@cvt (<|> LP $($optail)*) $postfix $($tail)*) };

    (@cvt (LP $($optail:tt)*) $postfix:tt *> $($tail:tt)*) => { infix!(@cvt (*> LP $($optail)*) $postfix $($tail)*) };
    //(@cvt (LP $($optail:tt)*) $postfix:tt / $($tail:tt)*) => { infix!(@cvt (/ LP $($optail)*) $postfix $($tail)*) };
    
    // 3. push a left-paren onto the stack
    (@cvt ($($operator:tt)*) $postfix:tt ($($inner:tt)*) $($tail:tt)*) => { infix!(@cvt (LP $($operator)*) $postfix $($inner)* RP $($tail)*) };
    
    // 4. see right-paren, pop operators to postfix until left-paren
    (@cvt (LP         $($optail:tt)*) $postfix:tt       RP $($tail:tt)*) => { infix!(@cvt ($($optail)*) $postfix               $($tail)*)    };
    (@cvt ($ophead:tt $($optail:tt)*) ($($postfix:tt)*) RP $($tail:tt)*) => { infix!(@cvt ($($optail)*) ($($postfix)* $ophead) RP $($tail)*) };
    
    // 5. if an operator w/ lower precedence is on top, just push
    (@cvt (<|> $($optail:tt)*) $postfix:tt *> $($tail:tt)*) => { infix!(@cvt (*> <|> $($optail)*) $postfix $($tail)*) };
    //(@cvt (- $($optail:tt)*) $postfix:tt * $($tail:tt)*) => { infix!(@cvt (* - $($optail)*) $postfix $($tail)*) };
    //(@cvt (+ $($optail:tt)*) $postfix:tt / $($tail:tt)*) => { infix!(@cvt (/ + $($optail)*) $postfix $($tail)*) };
    //(@cvt (- $($optail:tt)*) $postfix:tt / $($tail:tt)*) => { infix!(@cvt (/ - $($optail)*) $postfix $($tail)*) };
    
    // 6. if an operator w/ equal precedence is on top, pop and push
    (@cvt (<|> $($optail:tt)*) ($($postfix:tt)*) <|> $($tail:tt)*) => { infix!(@cvt (<|> $($optail)*) ($($postfix)* <|>) $($tail)*) };



    (@cvt (*> $($optail:tt)*) ($($postfix:tt)*) *> $($tail:tt)*) => { infix!(@cvt (*> $($optail)*) ($($postfix)* *>) $($tail)*) };
    //(@cvt (/ $($optail:tt)*) ($($postfix:tt)*) / $($tail:tt)*) => { infix!(@cvt (/ $($optail)*) ($($postfix)* /) $($tail)*) };
    //(@cvt (* $($optail:tt)*) ($($postfix:tt)*) / $($tail:tt)*) => { infix!(@cvt (/ $($optail)*) ($($postfix)* *) $($tail)*) };
    //(@cvt (/ $($optail:tt)*) ($($postfix:tt)*) * $($tail:tt)*) => { infix!(@cvt (* $($optail)*) ($($postfix)* /) $($tail)*) };
    
    // 7. if an operator w/ higher precedence is on top, pop it to postfix
    (@cvt (*> $($optail:tt)*) ($($postfix:tt)*) <|> $($tail:tt)*) => { infix!(@cvt ($($optail)*) ($($postfix)* *>) <|> $($tail)*) };

    //(@cvt (/ $($optail:tt)*) ($($postfix:tt)*) + $($tail:tt)*) => { infix!(@cvt ($($optail)*) ($($postfix)* /) + $($tail)*) };

    
    // 1. operands go to the postfix output
    (@cvt $operators:tt ($($postfix:tt)*) $head:tt $($tail:tt)*) => { infix!(@cvt $operators ($($postfix)* ($head)) $($tail)*) };
    
    // postfix interpreter
    (@pfx ($result:expr                     ) (                     )) => { $result };
    (@pfx (($a:expr) ($b:expr) $($stack:tt)*) (<|>        $($tail:tt)*)) => { infix!(@pfx (((
        combinators::primitive_combinators::Alternative {
            parser_first:$b, 
            parser_second: $a,
            _t: std::marker::PhantomData
        }
    )) $($stack)*) ($($tail)*)) };

    (@pfx (($a:expr) ($b:expr) $($stack:tt)*) (*>        $($tail:tt)*)) => { infix!(@pfx (((
        combinators::non_primitive_combinators::ThenR{
            parser_first:$b, 
            parser_second: $a,
            _a: std::marker::PhantomData,
            _b: std::marker::PhantomData
        }
    )) $($stack)*) ($($tail)*)) };
    //(@pfx (($a:expr) ($b:expr) $($stack:tt)*) (/        $($tail:tt)*)) => { infix!(@pfx ((($b / $a)) $($stack)*) ($($tail)*)) };
    (@pfx ($($stack:tt)*                    ) ($head:tt $($tail:tt)*)) => { infix!(@pfx ($head       $($stack)*) ($($tail)*)) };
    
    ($($t:tt)*) => { infix!(@cvt () () $($t)*) }
    //                      |    |  |  ^ infix expression
    //                      |    |  ^ postfix expression
    //                      |    ^ operator stack
    //                      ^ convert infix to postfix
}





fn main() {
    let p1 = Char {c: 'a'};
    let p2 = Char {c: 'b'};
    let p3 = Char {c: 'c'};
    let p4 = Char {c: 'd'};
    let p5 = Char {c: 'e'};
    let p = infix!(p1 *> p2 <|> p3 *> p4 <|> p5);
    println!("{:#?}", p.parse("e"));

}