1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use parsers::basic::*;
use parsers::core::*;
use parsers::execution::*;
use parsers::flow::*;
use parsers::monadic::*;
use parsers::parser::*;
use parsers::response::Response;

//  -------------------------------------------------------------------------------------------------
// Parser type definition
//  -------------------------------------------------------------------------------------------------

impl Parser<u8> for u8 {}

impl Parser<char> for char {}

impl Parser<String> for String {}

//  -------------------------------------------------------------------------------------------------

pub fn digit() -> FMap<TakeOne, u8, char> {
    take_one(Box::new(|a| {
        match *a as char {
            '0'...'9' => true,
            _ => false
        }
    })).fmap(Box::new(|a| a as char))
}

pub fn letter() -> FMap<TakeOne, u8, char> {
    take_one(Box::new(|a| {
        match *a as char {
            'a'...'z' => true,
            'A'...'Z' => true,
            _ => false
        }
    })).fmap(Box::new(|a| a as char))
}

pub fn float() -> Parsec<f32> {
    let p = opt('+'.or('-'))
        .then(digit().rep())
        .then(opt('.'.then_right(digit().rep())))
        .fmap(Box::new(|((a, b), c)| {
            let mut number = b.into_iter().collect::<String>();

            if let Some(v) = c {
                number.push_str(".");
                number.push_str(&v.into_iter().collect::<String>());
            };

            let result = number.parse::<f32>().unwrap();

            match a {
                Some('-') => -1f32 * result,
                _ => result
            }
        }));

    parsec(Box::new(p))
}

pub fn string_delim() -> Parsec<String> {
    let p = '"'.
        then_right("\\\"".to_string().fmap(Box::new(|_| '\"')).or(take_one(Box::new(|c| *c != '"' as u8)).fmap(Box::new(|a| a as char))).optrep())
        .then_left('"')
        .fmap(Box::new(|b| b.into_iter().collect::<String>()));

    parsec(Box::new(p))
}

pub fn char_delim() -> Parsec<char> {
    let p = '\''
        .then_right("\\\'".to_string().fmap(Box::new(|_| '\'')).or(take_one(Box::new(|c| *c != '\'' as u8)).fmap(Box::new(|a| a as char))))
        .then_left('\'');

    parsec(Box::new(p))
}

// -------------------------------------------------------------------------------------------------
// Parser execution
// -------------------------------------------------------------------------------------------------

impl Executable<u8> for u8 {
    fn execute(&self, s: &[u8], o: usize) -> Response<u8> {
        let r = any().execute(s, o);
        match r {
            Response::Success(a, _, _) if { *self == a } => r,
            _ => Response::Reject(o, false)
        }
    }
}

impl Executable<char> for char {
    fn execute(&self, s: &[u8], o: usize) -> Response<char> {
        let r = any().execute(s, o); // TODO unicode to be managed here
        match r {
            Response::Success(a, o, b) if { *self == a as char } => Response::Success(a as char, o, b),
            _ => Response::Reject(o, false)
        }
    }
}

// -------------------------------------------------------------------------------------------------

impl Executable<String> for String {
    fn execute(&self, s: &[u8], o: usize) -> Response<String> {
        if o + self.len() > s.len() {
            return Response::Reject(o, false);
        }

        let b = self.as_bytes();

        for i in 0..self.len() {
            if s[i + o] != b[i] {
                return Response::Reject(o, false);
            }
        }

        Response::Success(self.get(o..o + self.len()).unwrap().to_string(), o + self.len(), self.len() > 0)
    }
}

// -------------------------------------------------------------------------------------------------