nom-operator 0.0.2

Precedence climbing operator parser written with nom
Documentation
// Copyright 2017 The nom-operator project developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

macro_rules! testcase {
    ($name: ident, $input: expr, $res: expr) => {
        #[test]
        fn $name() {
            let mut opp = opparser_factory();
            assert_eq!(
                opp.parse($input),
                IResult::Done("".as_bytes(), $res)
            );
        }
    }
}

// Test macro
macro_rules! t {
    ($left: expr, $op: expr, $right: expr) => {
        $crate::Expr::BinExpr {
            left: Box::new($left),
            op: $op,
            right: Box::new($right),
        }
    };
    ($op: expr, $left: expr) => {
        $crate::Expr::UnExpr {
            item: Box::new($left),
            op: $op,
        }
    };
    ($a: expr) => {
        $crate::Expr::Atom(format!("{}", $a).as_bytes())
    };
}

// TODO: Tests for this macro
/// Matches a token and returns an operator with info
#[macro_export]
#[doc(hidden)]
macro_rules! alt_operator {
    (__impl $i:expr,
            $op_path: path,
            $token: path,
            $assoc: expr,
            $prec: expr => $($rest:tt)* ) => (

        alt_operator!(__impl $i, $op_path, call!($token), $assoc, $prec => $($rest)*);

    );

    (__impl $i:expr,
            $op_path: path,
            $token: ident!( $($token_args:tt)* ),
            $assoc: expr,
            $prec: expr => $($rest:tt)*) => (

        match $token!( $i, $($token_args)* ) {
            $crate::IResult::Error(_)      => {
                alt_operator!(__impl $i, $($rest)* )
            },
            $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
            $crate::IResult::Done(i, _)     => {
                $crate::IResult::Done(i, OperatorInfo {
                    op: $op_path,
                    associativity: $assoc,
                    precedence: $prec,
                })
            }
        }

    );

    (__impl $i:expr,
            $op_path: path,
            $token: path,
            $assoc: expr,
            $prec: expr) => (

        alt_operator!(__impl $i, $op_path, call!($token), $assoc, $prec, $($rest)*);

    );


    (__impl $i:expr,
            $op_path: path,
            $token: ident!( $($token_args:tt)* ),
            $assoc: expr,
            $prec: expr) => (

        match $token!( $i, $($token_args)* ) {
            $crate::IResult::Error(e)      => $crate::IResult::Error(e),
            $crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
            $crate::IResult::Done(i, _)     => {
                $crate::IResult::Done(i, OperatorInfo {
                    op: $op_path,
                    associativity: $assoc,
                    precedence: $prec,
                })
            }
        }

    );

    ($i:expr, $($rest:tt)*) => (
        {
            alt_operator!(__impl $i, $($rest)*)
        }
    );
}

/// Extract a result from a sucessful parse
/// return Incomplete or Error otherwise
#[macro_export]
#[doc(hidden)]
macro_rules! extract_result {
    ( $($input:tt)* ) => {
        match $($input)* {
            $crate::IResult::Incomplete(x) => {
                return $crate::IResult::Incomplete(x);
            },
            $crate::IResult::Error(e) => {
                return $crate::IResult::Error(e);
            },
            $crate::IResult::Done(i, o) => (i, o),
        }
    }
}

/// Parses an input expression according to the operators defined in the
/// arguments
#[macro_export]
macro_rules! parse_operator {
    (__impl
     $i: expr,
     // TODO: the final macro ideally wouldn't require type info
     <$ty: ty, $op_ty: ty>,
     $atom: path,
     $($ops:tt)*) => {
        parse_operator!(__impl $i, <$ty, $op_ty>, call!($atom), $($ops)*)
    };

    (__impl
     $i: expr,
     // TODO: the final macro ideally wouldn't require type info
     <$ty: ty, $op_ty: ty>,
     $atom: ident!( $($atom_args:tt)* ),
     $($ops:tt)*) => {{
       use $crate::Expr;
       use OperatorInfo;
       fn recurse(i: &[u8], min_prec: u32) ->
           $crate::IResult<&[u8], Expr<$ty, $op_ty>> {
       }
       recurse($i, 0)
    }};

    ($i: expr, <$ty: ty, $op_ty: ty>, $($rest:tt)* ) => {
        parse_operator!(__impl $i, <$ty, $op_ty>, $($rest)*)
    }
}