textmate_scope_selector_peg/
lib.rs1extern crate peg;
2
3pub use peg::{error::ParseError, str::LineCol};
4
5pub mod matchers;
6
7peg::parser! {
8 pub grammar parser() for str {
9 rule _() = quiet!{ [' ' | '\t']* }
11 rule ws() = quiet!{ [' ' | '\t']+ }
12
13 pub rule parse() -> Box<dyn matchers::Matcher>
15 = _ selector:selector() _ {
16 selector
17 }
18
19 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 rule scope() -> Box<dyn matchers::Matcher>
30 = atoms:atom() ++ "." {
31 Box::new(matchers::ScopeMatcher::new(atoms))
32 }
33
34 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 rule group() -> Box<dyn matchers::Matcher>
42 = prefix:$(['L'|'R'|'B'] ":")? "(" _ selector:selector() _ ")" {
43 Box::new(matchers::GroupMatcher::new(prefix, selector))
44 }
45
46 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 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 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}