#![feature(macro_rules)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
extern crate regex;
pub use self::ParserResult::{Succ, Fail, Error};
use std::cmp::{min, Ordering};
pub use re::re;
pub use chainl::chainl;
pub use chainr::chainr;
pub use choice::choice;
pub use until::until;
pub use many::many;
pub use many1::many1;
pub use keyword::keyword;
pub use try::try;
pub use skip::skip;
pub use cond::cond;
pub use opt::opt;
pub use wrapper::wrap;
pub use split::split;
pub use many_until::many_until;
pub mod re;
pub mod chainl;
pub mod chainr;
pub mod choice;
pub mod until;
pub mod many;
pub mod many1;
pub mod keyword;
pub mod try;
pub mod skip;
pub mod cond;
pub mod opt;
pub mod wrapper;
pub mod split;
pub mod many_until;
mod macros;
pub struct CharSeq<'a> {
pub pos: uint,
pub text: String,
pub place: String,
hooks: Vec<&'a (ParserHook+'a)>,
pub enable_hook: bool,
pub trace: bool
}
#[derive(Clone, Show)]
pub struct LocationInfo {
pub col: uint,
pub row: uint,
pub pos: uint,
pub place: String
}
impl Ord for LocationInfo {
fn cmp(&self, other: &LocationInfo) -> Ordering {
if self.row == other.row {
self.col.cmp(&other.col)
} else {
self.row.cmp(&other.row)
}
}
}
impl PartialOrd for LocationInfo {
fn partial_cmp(&self, other: &LocationInfo) -> Option<Ordering> {
Some(self.pos.cmp(&other.pos))
}
fn lt(&self, other: &LocationInfo) -> bool {
self.pos < other.pos
}
fn le(&self, other: &LocationInfo) -> bool {
self.pos <= other.pos
}
fn gt(&self, other: &LocationInfo) -> bool {
self.pos > other.pos
}
fn ge(&self, other: &LocationInfo) -> bool {
self.pos >= other.pos
}
}
impl PartialEq for LocationInfo {
fn eq(&self, other: &LocationInfo) -> bool {
self.pos == other.pos
}
}
impl Eq for LocationInfo {
}
#[derive(Show)]
pub enum ParserResult<T> {
Succ(T),
Error(String, LocationInfo),
Fail(String, LocationInfo),
}
impl<T> ParserResult<T> {
pub fn map<S>(self, f: |T| -> S) -> ParserResult<S> {
match self {
Succ(c) => Succ(f(c)),
Fail(m, l) => Fail(m.clone(), l.clone()),
Error(m, l) => Error(m.clone(), l.clone())
}
}
pub fn and_then<S>(self, f: |T| -> ParserResult<S>) -> ParserResult<S> {
match self {
Succ(c) => f(c),
Fail(m, l) => Fail(m.clone(), l.clone()),
Error(m, l) => Error(m.clone(), l.clone())
}
}
}
impl<'a> CharSeq<'a> {
pub fn view(&self) -> &str {
return self.text.slice_from(self.pos);
}
pub fn eof(&self) -> bool {
return self.text.len() <= self.pos;
}
pub fn new(t: &str, l: &str) -> CharSeq<'a> {
return CharSeq{pos: 0u, text: t.to_string(), place: l.to_string(), hooks: Vec::new(), enable_hook: true, trace: false};
}
pub fn fail<T>(&self, msg: &str) -> ParserResult<T> {
return Fail(msg.to_string(), self.get_location());
}
pub fn get_location(&self) -> LocationInfo {
let mut col = 1u;
let mut row = 1u;
let max = self.pos;
let mut i = 0;
for c in self.text.chars() {
if i >= max {
break;
}
col += 1;
if c == '\n' {
row += 1;
col = 1;
}
i+=1;
}
return LocationInfo{col: col, row:row, pos: self.pos, place: self.place.clone()};
}
pub fn current(&self) -> char {
if self.eof() {
return '\0';
} else {
return self.text.as_slice().char_at(self.pos);
}
}
pub fn next(&mut self) {
if !self.eof() {
self.pos += 1;
}
}
pub fn add_hook(&mut self, hook: &'a (ParserHook+'a)) {
self.hooks.push(hook);
}
#[allow(unused_variables)]
pub fn do_hook(&mut self) {
if !self.enable_hook {
return ();
}
self.enable_hook = false;
for h in self.hooks.clone().iter() {
h.hook(self);
}
self.enable_hook = true;
return ();
}
pub fn accept<T>(&mut self, p: &Parser<T>) -> ParserResult<T> {
if self.trace {
println!("{}", self.get_location());
}
return p.parse(self);
}
}
pub trait Parser<T> {
fn parse(&self, cs: &mut CharSeq) -> ParserResult<T> {
cs.do_hook();
let r = self._parse(cs);
cs.do_hook();
return r;
}
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<T>;
#[allow(unused_variables)]
fn lookahead(&self, cs: &mut CharSeq) -> bool {
let p = cs.pos;
let result = match self.parse(cs) {
Succ(c) => true,
Fail(m, l) => false,
Error(m, l) => false
};
cs.pos = p;
return result;
}
}
pub trait ParserHook {
fn hook(&self, cs: &mut CharSeq);
}
impl<'a> Parser<String> for &'a str {
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<String> {
if cs.view().slice_to(min(self.len(), cs.view().len())) == *self {
cs.pos = cs.pos + self.len();
return Succ(self.to_string().clone());
} else {
return cs.fail(*self);
}
}
}
#[derive(Copy)]
pub struct EOF;
impl Parser<()> for EOF {
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<()> {
if cs.eof() {
Succ(())
} else {
cs.fail("not eof")
}
}
}
#[cfg(test)]
#[allow(unused_variables)]
#[allow(unused_imports)]
mod tests {
use super::{CharSeq, ParserResult, Parser, Succ, Fail, Error};
#[test]
fn test_s1() {
let mut cs = CharSeq::new("abcabcdef", "<mem>");
assert!(cs.pos == 0);
match cs.accept(&"abc") {
Succ(a) => assert!(a.as_slice() == "abc"),
_ => assert!(false, "bug")
}
assert!(cs.pos == 3);
assert!(cs.view() == "abcdef");
match cs.accept(&"abc") {
Succ(a) => assert!(a.as_slice() == "abc"),
_ => assert!(false, "bug")
}
assert!(cs.pos == 6);
assert!(cs.view() == "def");
match cs.accept(&"abc") {
Succ(a) => assert!(false, format!("unexcepted result: {}, pos:{}", a, cs.pos)),
Fail(a, b) => (),
Error(a, b) => assert!(false, "error")
}
assert!(cs.pos == 6);
match cs.accept(&"def") {
Succ(a) => assert!(a.as_slice()=="def"),
_ => assert!(false, "bug")
}
assert!(cs.pos == 9);
assert!(cs.eof());
match cs.accept(&"def") {
Succ(a) => assert!(false, format!("unexcepted result: {}, pos: {}", a , cs.pos)),
Fail(a, b) => (),
Error(a, b) => assert!(false, "error")
}
assert!(cs.pos == 9);
assert!(cs.eof());
}
#[test]
fn test_s2() {
let mut cs = CharSeq::new("abcdefghi", "<mem>");
let r = cs.accept(&"abc").map(
|a| cs.accept(&"def").map(
|b| cs.accept(&"ghi").map(
|c| {
assert!(a.as_slice() == "abc");
assert!(b.as_slice() == "def");
assert!(c.as_slice() == "ghi");
}
)
)
);
}
#[test]
fn test_s3() {
let mut cs = CharSeq::new("a", "<mem>");
match cs.accept(&"abc") {
Succ(a) => assert!(false, format!("unexcepted result: {}, pos: {}", a , cs.pos)),
Fail(a, b) => (),
Error(a, b) => assert!(false, "error")
}
}
}