textmate_scope_selector_peg/
lib.rs

1extern crate peg;
2
3pub use peg::{error::ParseError, str::LineCol};
4
5pub mod matchers;
6
7peg::parser! {
8    pub grammar parser() for str {
9        // Skip whitespace
10        rule _() = quiet!{ [' ' | '\t']* }
11        rule ws() = quiet!{ [' ' | '\t']+ }
12
13        // Starting rule
14        pub rule parse() -> Box<dyn matchers::Matcher>
15            = _ selector:selector() _ {
16                selector
17            }
18
19        // Atom matchers
20        rule atom() -> Box<dyn matchers::Matcher>
21            = segment:$(!['-']['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '+']+) {
22                Box::new(matchers::SegmentMatcher::new(segment))
23            }
24            / "*" {
25                Box::new(matchers::TrueMatcher{})
26            }
27
28        // Scope matcher
29        rule scope() -> Box<dyn matchers::Matcher>
30            = atoms:atom() ++ "." {
31                Box::new(matchers::ScopeMatcher::new(atoms))
32            }
33
34        // Path matcher
35        rule path() -> Box<dyn matchers::Matcher>
36            = prefix:$(['L'|'R'|'B'] ":")? scopes:scope() ++ ws() {
37                Box::new(matchers::PathMatcher::new(prefix, scopes))
38            }
39
40        // Group matcher
41        rule group() -> Box<dyn matchers::Matcher>
42            = prefix:$(['L'|'R'|'B'] ":")? "(" _ selector:selector() _ ")" {
43                Box::new(matchers::GroupMatcher::new(prefix, selector))
44            }
45
46        // Expression matcher
47        rule expression() -> Box<dyn matchers::Matcher>
48            = "-" _ group:group() _ {
49                Box::new(matchers::NegateMatcher::new(group))
50            }
51            / "-" _ path:path() _ {
52                Box::new(matchers::NegateMatcher::new(path))
53            }
54            / group()
55            / path()
56
57        // Composite matcher
58        rule composite() -> Box<dyn matchers::Matcher>
59            = left:expression() _ operator:$(['|' | '&' | '-']) _ right:composite() {
60                Box::new(matchers::CompositeMatcher::new(left, operator.chars().next().unwrap(), right))
61            }
62            / expression()
63
64        // Selector matcher
65        rule selector() -> Box<dyn matchers::Matcher>
66            = left:composite() _ "," _ right:selector()? {
67                if let Some(r) = right {
68                    Box::new(matchers::OrMatcher::new(left, r))
69                } else {
70                    left
71                }
72            }
73            / composite()
74    }
75}
76
77pub fn parse(selector: &str) -> Result<Box<dyn matchers::Matcher>, ParseError<LineCol>> {
78    return parser::parse(selector);
79}