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 { |
30 | fn p(&self, s: &[u8]) -> Option<usize>; |
31 | } |
32 | |
33 | impl<F: Fn(&[u8]) -> Option<usize>> Recognize for F { |
34 | #[inline (always)] |
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)] |
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)] |
55 | fn p(&self, s: &[u8]) -> Option<usize> { |
56 | OneByte(|b: u8| 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)] |
66 | fn p(&self, s: &[u8]) -> Option<usize> { |
67 | OneByte(|x: u8| x >= self.0.start && x <= self.0.end).p(s) |
68 | } |
69 | } |
70 | |
71 | impl<'a> Recognize for &'a [u8] { |
72 | #[inline (always)] |
73 | fn p(&self, s: &[u8]) -> Option<usize> { |
74 | let len: usize = 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)] |
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)] |
92 | fn p(&self, s: &[u8]) -> Option<usize> { |
93 | self.0.p(s).and_then(|len1: usize| |
94 | self.1.p(&s[len1..]).map(|len2: usize| |
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)] |
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 ] |
114 | fn p(&self, s: &[u8]) -> Option<usize> { |
115 | for ref p: &&'a P in self.0 { |
116 | if let Some(len: usize) = 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 ] |
128 | fn p(&self, s: &[u8]) -> Option<usize> { |
129 | let mut i: usize = 0; |
130 | let mut count: i32 = 0; |
131 | while let Some(len: usize) = 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 ] |
147 | fn p(&self, s: &[u8]) -> Option<usize> { |
148 | let mut i: usize = 0; |
149 | while let Some(len: usize) = self.0.p(&s[i..]) { |
150 | i += len; |
151 | } |
152 | Some(i) |
153 | } |
154 | } |
155 | |