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: &Ident)) if i.to_string() == "stable" => parse_stable(iter), |
55 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "beta" => Ok(Expr::Beta), |
56 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "nightly" => parse_nightly(iter), |
57 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "since" => parse_since(introducer:i, iter), |
58 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "before" => parse_before(introducer:i, iter), |
59 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "not" => parse_not(introducer:i, iter), |
60 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "any" => parse_any(introducer:i, iter), |
61 | Some(TokenTree::Ident(i: &Ident)) if i.to_string() == "all" => parse_all(introducer:i, iter), |
62 | unexpected: &Option => { |
63 | let span: Span = unexpected |
64 | .as_ref() |
65 | .map_or_else(default:Span::call_site, f:TokenTree::span); |
66 | Err(Error::new(span, msg:"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: Group = match token::parse_optional_paren(iter) { |
73 | Some(group: Group) => group, |
74 | None => return Ok(Expr::Nightly), |
75 | }; |
76 | |
77 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
78 | let date: Date = date::parse(paren, iter:inner)?; |
79 | token::parse_optional_punct(iter:inner, ch:',' ); |
80 | token::parse_end(iter:inner)?; |
81 | |
82 | Ok(Expr::Date(date)) |
83 | } |
84 | |
85 | fn parse_stable(iter: Iter) -> Result<Expr> { |
86 | let paren: Group = match token::parse_optional_paren(iter) { |
87 | Some(group: Group) => group, |
88 | None => return Ok(Expr::Stable), |
89 | }; |
90 | |
91 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
92 | let release: Release = release::parse(paren, iter:inner)?; |
93 | token::parse_optional_punct(iter:inner, ch:',' ); |
94 | token::parse_end(iter:inner)?; |
95 | |
96 | Ok(Expr::Release(release)) |
97 | } |
98 | |
99 | fn parse_since(introducer: &Ident, iter: Iter) -> Result<Expr> { |
100 | let paren: Group = token::parse_paren(introducer, iter)?; |
101 | |
102 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
103 | let bound: Bound = bound::parse(paren, iter:inner)?; |
104 | token::parse_optional_punct(iter:inner, ch:',' ); |
105 | token::parse_end(iter:inner)?; |
106 | |
107 | Ok(Expr::Since(bound)) |
108 | } |
109 | |
110 | fn parse_before(introducer: &Ident, iter: Iter) -> Result<Expr> { |
111 | let paren: Group = token::parse_paren(introducer, iter)?; |
112 | |
113 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
114 | let bound: Bound = bound::parse(paren, iter:inner)?; |
115 | token::parse_optional_punct(iter:inner, ch:',' ); |
116 | token::parse_end(iter:inner)?; |
117 | |
118 | Ok(Expr::Before(bound)) |
119 | } |
120 | |
121 | fn parse_not(introducer: &Ident, iter: Iter) -> Result<Expr> { |
122 | let paren: Group = token::parse_paren(introducer, iter)?; |
123 | |
124 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
125 | let expr: Expr = self::parse(iter:inner)?; |
126 | token::parse_optional_punct(iter:inner, ch:',' ); |
127 | token::parse_end(iter:inner)?; |
128 | |
129 | Ok(Expr::Not(Box::new(expr))) |
130 | } |
131 | |
132 | fn parse_any(introducer: &Ident, iter: Iter) -> Result<Expr> { |
133 | let paren: Group = token::parse_paren(introducer, iter)?; |
134 | |
135 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
136 | let exprs: Vec = parse_comma_separated(iter: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: Group = token::parse_paren(introducer, iter)?; |
143 | |
144 | let ref mut inner: &mut IterImpl = iter::new(tokens:paren.stream()); |
145 | let exprs: Vec = parse_comma_separated(iter: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 = Vec::new(); |
152 | |
153 | while iter.peek().is_some() { |
154 | let expr: Expr = self::parse(iter)?; |
155 | exprs.push(expr); |
156 | if iter.peek().is_none() { |
157 | break; |
158 | } |
159 | token::parse_punct(iter, ch:',' )?; |
160 | } |
161 | |
162 | Ok(exprs) |
163 | } |
164 | |