tagua_parser/rules/
tokens.rs

1// Tagua VM
2//
3//
4// New BSD License
5//
6// Copyright © 2016-2016, Ivan Enderlin.
7// All rights reserved.
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are met:
11//     * Redistributions of source code must retain the above copyright
12//       notice, this list of conditions and the following disclaimer.
13//     * Redistributions in binary form must reproduce the above copyright
14//       notice, this list of conditions and the following disclaimer in the
15//       documentation and/or other materials provided with the distribution.
16//     * Neither the name of the Hoa nor the names of its contributors may be
17//       used to endorse or promote products derived from this software without
18//       specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
24// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30// POSSIBILITY OF SUCH DAMAGE.
31
32//! Group of token rules.
33//!
34//! The list of all tokens is provided by the PHP Language Specification in
35//! the [Grammar chapter, Tokens
36//! section](https://github.com/php/php-langspec/blob/master/spec/19-grammar.md#tokens).
37
38use super::super::tokens;
39use super::super::ast::{
40    Name,
41    Variable
42};
43
44named!(
45    pub variable<Variable>,
46    map_res!(
47        preceded!(
48            tag!(tokens::VARIABLE),
49            name
50        ),
51        variable_mapper
52    )
53);
54
55#[inline(always)]
56fn variable_mapper(string: &[u8]) -> Result<Variable, ()> {
57    Ok(Variable(string))
58}
59
60named!(
61    pub qualified_name<Name>,
62    chain!(
63        head: alt!(
64            tag!(tokens::NAMESPACE_SEPARATOR)
65          | terminated!(
66                keyword!(tokens::NAMESPACE),
67                first!(tag!(tokens::NAMESPACE_SEPARATOR))
68            )
69        )? ~
70        mut accumulator: map_res!(
71            exclude!(first!(name), tokens::keywords),
72            wrap_into_vector_mapper
73        ) ~
74        many0!(
75            tap!(
76                tail: preceded!(
77                    first!(tag!(tokens::NAMESPACE_SEPARATOR)),
78                    exclude!(first!(name), tokens::keywords)
79                ) =>
80                    accumulator.push(tail)
81            )
82        ),
83        || {
84            match head {
85                Some(handle) =>
86                    if handle == tokens::NAMESPACE_SEPARATOR {
87                        Name::FullyQualified(accumulator)
88                    } else {
89                        Name::RelativeQualified(accumulator)
90                    },
91
92                None =>
93                    if accumulator.len() > 1 {
94                        Name::Qualified(accumulator)
95                    } else {
96                        Name::Unqualified(accumulator[0])
97                    }
98            }
99        }
100    )
101);
102
103#[inline(always)]
104fn wrap_into_vector_mapper(string: &[u8]) -> Result<Vec<&[u8]>, ()> {
105    Ok(vec![string])
106}
107
108named!(
109    pub name,
110    re_bytes_find_static!(r"^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*")
111);
112
113
114#[cfg(test)]
115mod tests {
116    use super::{
117        name,
118        qualified_name,
119        variable
120    };
121    use super::super::super::ast::{
122        Name,
123        Variable
124    };
125    use super::super::super::internal::{
126        Error,
127        ErrorKind,
128        Result
129    };
130    use super::super::super::macros::ErrorKindCustom;
131
132    #[test]
133    fn case_variable() {
134        assert_eq!(variable(b"$foo"), Result::Done(&b""[..], Variable(&b"foo"[..])));
135    }
136
137    #[test]
138    fn case_variable_shortest() {
139        assert_eq!(variable(b"$x"), Result::Done(&b""[..], Variable(&b"x"[..])));
140    }
141
142    #[test]
143    fn case_invalid_variable_prefix() {
144        assert_eq!(variable(b"x"), Result::Error(Error::Position(ErrorKind::Tag, &b"x"[..])));
145    }
146
147    #[test]
148    fn case_invalid_variable_name() {
149        assert_eq!(variable(b"$0"), Result::Error(Error::Code(ErrorKind::RegexpFind)));
150    }
151
152    #[test]
153    fn case_unqualified_name() {
154        assert_eq!(qualified_name(b"Foo"), Result::Done(&b""[..], Name::Unqualified(&b"Foo"[..])));
155    }
156
157    #[test]
158    fn case_invalid_unqualified_name() {
159        assert_eq!(qualified_name(b"class"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"class"[..])));
160        assert_eq!(qualified_name(b"ClAsS"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"ClAsS"[..])));
161    }
162
163    #[test]
164    fn case_qualified_name() {
165        assert_eq!(qualified_name(b"Foo\\Bar\\Baz"), Result::Done(&b""[..], Name::Qualified(vec![&b"Foo"[..], &b"Bar"[..], &b"Baz"[..]])));
166    }
167
168    #[test]
169    fn case_qualified_name_with_skip_tokens() {
170        assert_eq!(qualified_name(b"Foo\n/* baz */ \\ Bar /* qux */\\"), Result::Done(&b" /* qux */\\"[..], Name::Qualified(vec![&b"Foo"[..], &b"Bar"[..]])));
171    }
172
173    #[test]
174    fn case_invalid_qualified_name() {
175        assert_eq!(qualified_name(b"Foo\\class\\Baz"), Result::Done(&b"\\class\\Baz"[..], Name::Unqualified(&b"Foo"[..])));
176        assert_eq!(qualified_name(b"Foo\\ClAsS\\Baz"), Result::Done(&b"\\ClAsS\\Baz"[..], Name::Unqualified(&b"Foo"[..])));
177    }
178
179    #[test]
180    fn case_relative_qualified_name() {
181        assert_eq!(qualified_name(b"namespace\\Foo\\Bar\\Baz"), Result::Done(&b""[..], Name::RelativeQualified(vec![&b"Foo"[..], &b"Bar"[..], &b"Baz"[..]])));
182    }
183
184    #[test]
185    fn case_relative_qualified_name_case_insensitive() {
186        assert_eq!(qualified_name(b"NaMeSpAcE\\Foo\\Bar\\Baz"), Result::Done(&b""[..], Name::RelativeQualified(vec![&b"Foo"[..], &b"Bar"[..], &b"Baz"[..]])));
187    }
188
189    #[test]
190    fn case_relative_qualified_name_with_skip_tokens() {
191        assert_eq!(qualified_name(b"namespace/* baz */ \\ Foo\n/* qux */ \\ Bar /* hello */\\"), Result::Done(&b" /* hello */\\"[..], Name::RelativeQualified(vec![&b"Foo"[..], &b"Bar"[..]])));
192    }
193
194    #[test]
195    fn case_invalid_relative_qualified_name_with_namespace() {
196        assert_eq!(qualified_name(b"namespace\\Foo\\namespace\\Baz"), Result::Done(&b"\\namespace\\Baz"[..], Name::RelativeQualified(vec![&b"Foo"[..]])));
197        assert_eq!(qualified_name(b"namespace\\Foo\\NaMeSpAcE\\Baz"), Result::Done(&b"\\NaMeSpAcE\\Baz"[..], Name::RelativeQualified(vec![&b"Foo"[..]])));
198    }
199
200    #[test]
201    fn case_invalid_relative_qualified_name_with_any_keyword() {
202        assert_eq!(qualified_name(b"namespace\\class"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"class"[..])));
203        assert_eq!(qualified_name(b"namespace\\ClAsS"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"ClAsS"[..])));
204    }
205
206    #[test]
207    fn case_fully_qualified_name() {
208        assert_eq!(qualified_name(b"\\Foo\\Bar\\Baz"), Result::Done(&b""[..], Name::FullyQualified(vec![&b"Foo"[..], &b"Bar"[..], &b"Baz"[..]])));
209    }
210
211    #[test]
212    fn case_fully_qualified_shortest_name() {
213        assert_eq!(qualified_name(b"\\Foo"), Result::Done(&b""[..], Name::FullyQualified(vec![&b"Foo"[..]])));
214    }
215
216    #[test]
217    fn case_invalid_fully_and_relative_qualified_name_with_namespace() {
218        assert_eq!(qualified_name(b"\\namespace\\Foo\\Bar"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"namespace\\Foo\\Bar"[..])));
219    }
220
221    #[test]
222    fn case_invalid_fully_and_relative_qualified_name_with_any_keyword() {
223        assert_eq!(qualified_name(b"\\class\\Foo\\Bar"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"class\\Foo\\Bar"[..])));
224        assert_eq!(qualified_name(b"\\ClAsS\\Foo\\Bar"), Result::Error(Error::Position(ErrorKind::Custom(ErrorKindCustom::Exclude as u32), &b"ClAsS\\Foo\\Bar"[..])));
225    }
226
227    #[test]
228    fn case_invalid_qualified_name_ending_with_a_separator() {
229        assert_eq!(qualified_name(b"Foo\\Bar\\"), Result::Done(&b"\\"[..], Name::Qualified(vec![&b"Foo"[..], &b"Bar"[..]])));
230    }
231
232    #[test]
233    fn case_name() {
234        assert_eq!(name(b"_fooBar42"), Result::Done(&b""[..], &b"_fooBar42"[..]));
235    }
236
237    #[test]
238    fn case_name_shortest() {
239        assert_eq!(name(b"x"), Result::Done(&b""[..], &b"x"[..]));
240    }
241
242    #[test]
243    fn case_name_only_head() {
244        assert_eq!(name(b"aB_\x80"), Result::Done(&b""[..], &b"aB_\x80"[..]));
245    }
246
247    #[test]
248    fn case_name_head_and_tail() {
249        assert_eq!(name(b"aB_\x80aB7\xff"), Result::Done(&b""[..], &b"aB_\x80aB7\xff"[..]));
250    }
251
252    #[test]
253    fn case_name_copyright() {
254        // © = 0xa9
255        assert_eq!(name(b"\xa9"), Result::Done(&b""[..], &b"\xa9"[..]));
256    }
257
258    #[test]
259    fn case_name_non_breaking_space() {
260        //   = 0xa0
261        assert_eq!(name(b"\xa0"), Result::Done(&b""[..], &b"\xa0"[..]));
262    }
263
264    #[test]
265    fn case_invalid_name() {
266        assert_eq!(name(b"0x"), Result::Error(Error::Code(ErrorKind::RegexpFind)));
267    }
268}