]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use crate::bound::{self, Bound}; |
2 | use crate::date::{self, Date}; | |
3 | use crate::error::{Error, Result}; | |
4 | use crate::iter::{self, Iter}; | |
5 | use crate::release::{self, Release}; | |
6 | use crate::token; | |
7 | use crate::version::{Channel, Version}; | |
8 | use proc_macro::{Ident, Span, TokenTree}; | |
9 | ||
10 | pub enum Expr { | |
11 | Stable, | |
12 | Beta, | |
13 | Nightly, | |
14 | Date(Date), | |
15 | Since(Bound), | |
16 | Before(Bound), | |
17 | Release(Release), | |
18 | Not(Box<Expr>), | |
19 | Any(Vec<Expr>), | |
20 | All(Vec<Expr>), | |
21 | } | |
22 | ||
23 | impl Expr { | |
24 | pub fn eval(&self, rustc: Version) -> bool { | |
25 | use self::Expr::*; | |
26 | ||
27 | match self { | |
28 | Stable => rustc.channel == Channel::Stable, | |
29 | Beta => rustc.channel == Channel::Beta, | |
30 | Nightly => match rustc.channel { | |
31 | Channel::Nightly(_) | Channel::Dev => true, | |
32 | Channel::Stable | Channel::Beta => false, | |
33 | }, | |
34 | Date(date) => match rustc.channel { | |
35 | Channel::Nightly(rustc) => rustc == *date, | |
36 | Channel::Stable | Channel::Beta | Channel::Dev => false, | |
37 | }, | |
38 | Since(bound) => rustc >= *bound, | |
39 | Before(bound) => rustc < *bound, | |
40 | Release(release) => { | |
41 | rustc.channel == Channel::Stable | |
42 | && rustc.minor == release.minor | |
43 | && release.patch.map_or(true, |patch| rustc.patch == patch) | |
44 | } | |
45 | Not(expr) => !expr.eval(rustc), | |
46 | Any(exprs) => exprs.iter().any(|e| e.eval(rustc)), | |
47 | All(exprs) => exprs.iter().all(|e| e.eval(rustc)), | |
48 | } | |
49 | } | |
50 | } | |
51 | ||
52 | pub fn parse(iter: Iter) -> Result<Expr> { | |
53 | match &iter.next() { | |
54 | Some(TokenTree::Ident(i)) if i.to_string() == "stable" => parse_stable(iter), | |
55 | Some(TokenTree::Ident(i)) if i.to_string() == "beta" => Ok(Expr::Beta), | |
56 | Some(TokenTree::Ident(i)) if i.to_string() == "nightly" => parse_nightly(iter), | |
57 | Some(TokenTree::Ident(i)) if i.to_string() == "since" => parse_since(i, iter), | |
58 | Some(TokenTree::Ident(i)) if i.to_string() == "before" => parse_before(i, iter), | |
59 | Some(TokenTree::Ident(i)) if i.to_string() == "not" => parse_not(i, iter), | |
60 | Some(TokenTree::Ident(i)) if i.to_string() == "any" => parse_any(i, iter), | |
61 | Some(TokenTree::Ident(i)) if i.to_string() == "all" => parse_all(i, iter), | |
62 | unexpected => { | |
63 | let span = unexpected | |
64 | .as_ref() | |
65 | .map_or_else(Span::call_site, TokenTree::span); | |
66 | Err(Error::new(span, "expected one of `stable`, `beta`, `nightly`, `since`, `before`, `not`, `any`, `all`")) | |
67 | } | |
68 | } | |
69 | } | |
70 | ||
71 | fn parse_nightly(iter: Iter) -> Result<Expr> { | |
72 | let paren = match token::parse_optional_paren(iter) { | |
73 | Some(group) => group, | |
74 | None => return Ok(Expr::Nightly), | |
75 | }; | |
76 | ||
77 | let ref mut inner = iter::new(paren.stream()); | |
78 | let date = date::parse(paren, inner)?; | |
79 | token::parse_optional_punct(inner, ','); | |
80 | token::parse_end(inner)?; | |
81 | ||
82 | Ok(Expr::Date(date)) | |
83 | } | |
84 | ||
85 | fn parse_stable(iter: Iter) -> Result<Expr> { | |
86 | let paren = match token::parse_optional_paren(iter) { | |
87 | Some(group) => group, | |
88 | None => return Ok(Expr::Stable), | |
89 | }; | |
90 | ||
91 | let ref mut inner = iter::new(paren.stream()); | |
92 | let release = release::parse(paren, inner)?; | |
93 | token::parse_optional_punct(inner, ','); | |
94 | token::parse_end(inner)?; | |
95 | ||
96 | Ok(Expr::Release(release)) | |
97 | } | |
98 | ||
99 | fn parse_since(introducer: &Ident, iter: Iter) -> Result<Expr> { | |
100 | let paren = token::parse_paren(introducer, iter)?; | |
101 | ||
102 | let ref mut inner = iter::new(paren.stream()); | |
103 | let bound = bound::parse(paren, inner)?; | |
104 | token::parse_optional_punct(inner, ','); | |
105 | token::parse_end(inner)?; | |
106 | ||
107 | Ok(Expr::Since(bound)) | |
108 | } | |
109 | ||
110 | fn parse_before(introducer: &Ident, iter: Iter) -> Result<Expr> { | |
111 | let paren = token::parse_paren(introducer, iter)?; | |
112 | ||
113 | let ref mut inner = iter::new(paren.stream()); | |
114 | let bound = bound::parse(paren, inner)?; | |
115 | token::parse_optional_punct(inner, ','); | |
116 | token::parse_end(inner)?; | |
117 | ||
118 | Ok(Expr::Before(bound)) | |
119 | } | |
120 | ||
121 | fn parse_not(introducer: &Ident, iter: Iter) -> Result<Expr> { | |
122 | let paren = token::parse_paren(introducer, iter)?; | |
123 | ||
124 | let ref mut inner = iter::new(paren.stream()); | |
125 | let expr = self::parse(inner)?; | |
126 | token::parse_optional_punct(inner, ','); | |
127 | token::parse_end(inner)?; | |
128 | ||
129 | Ok(Expr::Not(Box::new(expr))) | |
130 | } | |
131 | ||
132 | fn parse_any(introducer: &Ident, iter: Iter) -> Result<Expr> { | |
133 | let paren = token::parse_paren(introducer, iter)?; | |
134 | ||
135 | let ref mut inner = iter::new(paren.stream()); | |
136 | let exprs = parse_comma_separated(inner)?; | |
137 | ||
138 | Ok(Expr::Any(exprs.into_iter().collect())) | |
139 | } | |
140 | ||
141 | fn parse_all(introducer: &Ident, iter: Iter) -> Result<Expr> { | |
142 | let paren = token::parse_paren(introducer, iter)?; | |
143 | ||
144 | let ref mut inner = iter::new(paren.stream()); | |
145 | let exprs = parse_comma_separated(inner)?; | |
146 | ||
147 | Ok(Expr::All(exprs.into_iter().collect())) | |
148 | } | |
149 | ||
150 | fn parse_comma_separated(iter: Iter) -> Result<Vec<Expr>> { | |
151 | let mut exprs = Vec::new(); | |
152 | ||
153 | while iter.peek().is_some() { | |
154 | let expr = self::parse(iter)?; | |
155 | exprs.push(expr); | |
156 | if iter.peek().is_none() { | |
157 | break; | |
158 | } | |
159 | token::parse_punct(iter, ',')?; | |
160 | } | |
161 | ||
162 | Ok(exprs) | |
163 | } |