1 // Copyright 2017 Google Inc. All rights reserved. 2 // 3 // Licensed under either of MIT or Apache License, Version 2.0, 4 // at your option. 5 // 6 // Use of this source code is governed by a MIT-style 7 // license that can be found in the LICENSE file or at 8 // https://opensource.org/licenses/MIT. 9 // 10 // Licensed under the Apache License, Version 2.0 (the "License"); 11 // you may not use this file except in compliance with the License. 12 // You may obtain a copy of the License at 13 // 14 // http://www.apache.org/licenses/LICENSE-2.0 15 // 16 // Unless required by applicable law or agreed to in writing, software 17 // distributed under the License is distributed on an "AS IS" BASIS, 18 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 // See the License for the specific language governing permissions and 20 // limitations under the License. 21 22 //! Simple recognizer combinators. 23 24 // This version is similar to a similar one in the "lang" module of 25 // xi-editor, but is stripped down to only the needed combinators. 26 27 use std::ops; 28 29 pub trait Recognize { p(&self, s: &[u8]) -> Option<usize>30 fn p(&self, s: &[u8]) -> Option<usize>; 31 } 32 33 impl<F: Fn(&[u8]) -> Option<usize>> Recognize for F { 34 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>35 fn p(&self, s: &[u8]) -> Option<usize> { 36 self(s) 37 } 38 } 39 40 pub struct OneByte<F>(pub F); 41 42 impl<F: Fn(u8) -> bool> Recognize for OneByte<F> { 43 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>44 fn p(&self, s: &[u8]) -> Option<usize> { 45 if s.is_empty() || !self.0(s[0]) { 46 None 47 } else { 48 Some(1) 49 } 50 } 51 } 52 53 impl Recognize for u8 { 54 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>55 fn p(&self, s: &[u8]) -> Option<usize> { 56 OneByte(|b| b == *self).p(s) 57 } 58 } 59 60 /// Use Inclusive(a..b) to indicate an inclusive range. When a...b syntax becomes 61 /// stable, we can get rid of this and switch to that. 62 pub struct Inclusive<T>(pub T); 63 64 impl Recognize for Inclusive<ops::Range<u8>> { 65 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>66 fn p(&self, s: &[u8]) -> Option<usize> { 67 OneByte(|x| x >= self.0.start && x <= self.0.end).p(s) 68 } 69 } 70 71 impl<'a> Recognize for &'a [u8] { 72 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>73 fn p(&self, s: &[u8]) -> Option<usize> { 74 let len = self.len(); 75 if s.len() >= len && &s[..len] == *self { 76 Some(len) 77 } else { 78 None 79 } 80 } 81 } 82 83 impl<'a> Recognize for &'a str { 84 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>85 fn p(&self, s: &[u8]) -> Option<usize> { 86 self.as_bytes().p(s) 87 } 88 } 89 90 impl<P1: Recognize, P2: Recognize> Recognize for (P1, P2) { 91 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>92 fn p(&self, s: &[u8]) -> Option<usize> { 93 self.0.p(s).and_then(|len1| 94 self.1.p(&s[len1..]).map(|len2| 95 len1 + len2)) 96 } 97 } 98 99 /// Choice from two heterogeneous alternatives. 100 pub struct Alt<P1, P2>(pub P1, pub P2); 101 102 impl<P1: Recognize, P2: Recognize> Recognize for Alt<P1, P2> { 103 #[inline(always)] p(&self, s: &[u8]) -> Option<usize>104 fn p(&self, s: &[u8]) -> Option<usize> { 105 self.0.p(s).or_else(|| self.1.p(s)) 106 } 107 } 108 109 /// Choice from a homogenous slice of parsers. 110 pub struct OneOf<'a, P: 'a>(pub &'a [P]); 111 112 impl<'a, P: Recognize> Recognize for OneOf<'a, P> { 113 #[inline] p(&self, s: &[u8]) -> Option<usize>114 fn p(&self, s: &[u8]) -> Option<usize> { 115 for ref p in self.0 { 116 if let Some(len) = p.p(s) { 117 return Some(len); 118 } 119 } 120 None 121 } 122 } 123 124 pub struct OneOrMore<P>(pub P); 125 126 impl<P: Recognize> Recognize for OneOrMore<P> { 127 #[inline] p(&self, s: &[u8]) -> Option<usize>128 fn p(&self, s: &[u8]) -> Option<usize> { 129 let mut i = 0; 130 let mut count = 0; 131 while let Some(len) = self.0.p(&s[i..]) { 132 i += len; 133 count += 1; 134 } 135 if count >= 1 { 136 Some(i) 137 } else { 138 None 139 } 140 } 141 } 142 143 pub struct ZeroOrMore<P>(pub P); 144 145 impl<P: Recognize> Recognize for ZeroOrMore<P> { 146 #[inline] p(&self, s: &[u8]) -> Option<usize>147 fn p(&self, s: &[u8]) -> Option<usize> { 148 let mut i = 0; 149 while let Some(len) = self.0.p(&s[i..]) { 150 i += len; 151 } 152 Some(i) 153 } 154 } 155