Skip to content

Instantly share code, notes, and snippets.

@tera3939
Created February 4, 2017 14:23
Show Gist options
  • Save tera3939/d5128350bc18091f20966a00d73d3416 to your computer and use it in GitHub Desktop.
Save tera3939/d5128350bc18091f20966a00d73d3416 to your computer and use it in GitHub Desktop.
パーサーコンビネータになりたかったもの
use std::ascii::AsciiExt;
use std::cell::{Cell, RefCell};
use std::error::Error;
use std::fmt;
#[derive(Debug)]
enum ParseError {
Parse,
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParseError::Parse => {write!(f, "Could not parse source in Source struct.")},
}
}
}
impl Error for ParseError {
fn description(&self) -> &str {
match *self {
ParseError::Parse => "Could not parse this string.",
}
}
}
type ParseResult<T> = Result<T, ParseError>;
#[derive(Debug)]
struct Source {
source: String,
part: RefCell<Option<String>>,
pos: Cell<usize>,
}
impl Source {
fn new<P: Into<String>> (s: P) -> Source {
Source {
source: s.into(),
part: RefCell::new(Some(String::with_capacity(1024))),
pos: Cell::new(0),
}
}
fn peek(&self) -> Option<char> {
self.source.chars().nth(self.pos.get())
}
fn next(&self) {
self.pos.set(self.pos.get() + 1);
}
}
trait Parser {
fn any_char(&self) -> &Source;
fn satisfy<F>(&self, f: F) -> &Source where F: FnOnce(char) -> bool;
fn replicate<F>(&self, n: usize, f: F) -> &Source where F: Fn(&Source) -> &Source;
fn many<F>(&self, f: F) -> &Source where F: Fn(&Source) -> &Source;
fn digit(&self) -> &Source;
fn upper(&self) -> &Source;
fn lower(&self) -> &Source;
fn alpha(&self) -> &Source;
fn alpha_num(&self) -> &Source;
fn letter(&self) -> &Source;
fn done(&self) -> ParseResult<String>;
}
impl Parser for Source {
fn satisfy<F>(&self, f: F) -> &Source
where F: FnOnce(char) -> bool{
/*
* 現在位置に文字があるか確認
* もしあるならその文字を関数fに渡す
* 真が帰ってきたときSource.partに追加
* 偽が帰ってきたときは何もしない // ここがよくない
* 文字がないならば何もしない
* その後Source.posを一つ進めてselfを返す
*/
match self.peek() {
Some(ch) => {
if f(ch) {
self.part
.borrow_mut()
.as_mut()
.map(|x| x.push(ch));
} else {
*self.part.borrow_mut() = None;
return self;
}
},
_ => {
*self.part.borrow_mut() = None;
return self;
},
};
self.next();
self
}
fn any_char(&self) -> &Source { self.satisfy(|x| true) }
fn digit(&self) -> &Source { self.satisfy(|x| x.is_digit(10)) }
fn upper(&self) -> &Source { self.satisfy(|x| x.is_uppercase()) }
fn lower(&self) -> &Source { self.satisfy(|x| x.is_lowercase()) }
fn alpha(&self) -> &Source { self.satisfy(|x| x.is_ascii()) }
fn alpha_num(&self) -> &Source { self.satisfy(|x| x.is_digit(10) || x.is_ascii()) }
fn letter(&self) -> &Source { self.satisfy(|x| x.is_alphabetic()) }
fn done(&self)-> ParseResult<String> {
self.part
.borrow()
.as_ref()
.ok_or(ParseError::Parse)
.map(|p|{
let mut s = String::with_capacity(p.len());
s.push_str(p);
s
})
}
fn replicate<F>(&self, n: usize, f: F) -> &Source
where F: Fn(&Source) -> &Source {
for i in 0..n {
f(self);
}
self
}
fn many<F>(&self, f: F) -> &Source where F: Fn(&Source) -> &Source {
}
}
macro_rules! char_to_string {
($ch_vec:expr) => {{
let mut s = String::new();
for ch in $ch_vec.iter() {
s.push(*ch);
}
s
}}
}
fn test(s: &str) -> ParseResult<String> {
let s = Source::new(s);
s.many(|x| x.alpha()).done()
}
fn main() {
let a = test("a12");
let b = test("ab1");
let c = test("abc");
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment