Skip to content

Instantly share code, notes, and snippets.

@syusui-s
Last active May 18, 2017 22:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syusui-s/95a67a4336e28f5635e30c1cc8548235 to your computer and use it in GitHub Desktop.
Save syusui-s/95a67a4336e28f5635e30c1cc8548235 to your computer and use it in GitHub Desktop.
「Java パーサコンビネータ 超入門」Rust version( http://qiita.com/7shi/items/68228e19552c271bea81
use std::error::Error;
use std::iter::FromIterator;
use std::fmt;
#[derive(Debug)]
struct ParseError {
message: &'static str,
}
impl ParseError {
fn new(message: &'static str) -> Self {
ParseError { message }
}
}
impl Error for ParseError {
fn description(&self) -> &str { self.message }
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "parse error: {}", self.message)
}
}
struct Source {
src: String,
pos: usize,
}
impl Source {
fn new(src: String) -> Self {
Self { src: src, pos: 0, }
}
fn from_str(src: &str) -> Self {
Self::new(src.into())
}
}
impl Iterator for Source {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
let result = self.src.chars().nth(self.pos);
self.pos += 1;
result
}
}
/////////////////////////////////////////////////////////////////////
type ParserResult<T> = Result<T, ParseError>;
type Parser<T> = fn(&mut Source) -> ParserResult<T>;
macro_rules! satisfy {
( $n:ident, $x:path $(, $a:expr )* ) => {
fn $n(src: &mut Source) -> ParserResult<char> {
match src.next() {
Some(ch) => {
if ($x)(ch$(, $a)*) { Ok(ch) }
else { Err(ParseError::new("not satisfy")) }
},
None => Err(ParseError::new("too short")),
}
}
};
}
macro_rules! or {
( $n:ident, $t:ty, $x:path, $y:path) => {
fn $n(src: &mut Source) -> ParserResult<$t> {
let pos = src.pos()
if let Ok(result) = ($x)(src) {
return Ok(result);
}
src.set_pos(pos);
if let Ok(result) = ($y)(src) {
return Ok(result);
} else {
return Err(ParseError::Ok);
}
}
};
}
fn any_char(s: &mut Source) -> ParserResult<char> {
s.next().ok_or(ParseError::new("too short"))
}
fn test1(s: &mut Source) -> ParserResult<String> {
let x1 = any_char(s)?;
let x2 = any_char(s)?;
let vec = [x1, x2];
Ok(String::from_iter(vec.iter()))
}
fn test2(s: &mut Source) -> ParserResult<String> {
let mut x1 = test1(s)?;
x1.push(any_char(s)?);
Ok(x1)
}
satisfy!(digit, char::is_digit, 10);
satisfy!(alpha, char::is_alphabetic);
or!(digit_or_alpha, char, digit, alpha);
fn parse_test<T>(func: Parser<T>, s: &str) -> ParserResult<T> {
let mut source = Source::from_str(s);
func(&mut source)
}
/////////////////////////////////////////////////////////////////////
fn main() {
println!("{:?}", parse_test(any_char, "abc"));
println!("{:?}", parse_test(test1, "abc"));
println!("{:?}", parse_test(test2, "abc"));
println!("{:?}", parse_test(digit, "123"));
println!("{:?}", parse_test(digit_or_alpha, "1"));
println!("{:?}", parse_test(digit_or_alpha, "a"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment