dat2 / graphql-rust

GraphQL in Rust!
MIT License
2 stars 0 forks source link

Combine macros #2

Closed dashed closed 8 years ago

dashed commented 8 years ago

version 1

pub struct LineTerminator<T> {
  phantom: PhantomData<T>,
}

impl<T> LineTerminator<T> {
  fn new() -> Self {
    LineTerminator {
      phantom: PhantomData
    }
  }
}

impl<I> Parser for LineTerminator<I> where I: Stream<Item=char> {
  type Input = I;
  type Output = char;

  fn parse_stream(&mut self, input: I) -> ParseResult<Self::Output, Self::Input> {
    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }
}
dashed commented 8 years ago

make_parser_struct macro

macro_rules! make_parser_struct {
  ($name: ident) => {
    pub struct $name<T> {
      phantom: PhantomData<T>,
    }

    impl<T> $name<T> {
      fn new() -> Self {
        $name {
          phantom: PhantomData
        }
      }
    }
  }
}
make_parser_struct!(LineTerminator);

impl<I> Parser for LineTerminator<I> where I: Stream<Item=char> {
  type Input = I;
  type Output = char;

  fn parse_stream(&mut self, input: I) -> ParseResult<Self::Output, Self::Input> {
    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }
}
dashed commented 8 years ago

make_parser macro

recognize macro inputs

impl<I> Parser for LineTerminator<I> where I: Stream<Item=$input_item_type> {
  type Input = I;
  type Output = $output_type;

  fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
    $content
  }
}

// macro'd by

make_parser!(
  LineTerminator($input_var: $input_item_type) -> $output_type {
    $content
  }
);

resulting macro

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      pub struct $name<T> {
        phantom: PhantomData<T>,
      }

      impl<T> $name<T> {
          pub fn new() -> Self {
              $name {
                phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        pub struct $name<'a, T> {
          phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T> $name<'a, T> {
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };

}
dashed commented 8 years ago

valid forms

make_parser!(
  LineTerminator(input: char) -> char {
    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }
);

make_parser!(
  Comment(input: char) -> char {
    char('#')
      .skip(LineTerminator::new())
      .parse_stream(input)
  }
);

make_parser!(
  LineTerminator(input: char) -> char {
    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }

  Comment(input: char) -> char {
    char('#')
      .skip(LineTerminator::new())
      .parse_stream(input)
  }
);
dashed commented 8 years ago

struct members

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      return char('\r')
        .or(char('\n'))
        .parse_stream(input);
    }

    crlf()
      .or(char('\r'))
      .or(char('\n'))
      .parse_stream(input)
  }
);

// usage ...

make_parser!(
  Comment(input: char) -> char {
    char('#')
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);