• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
eval(&self, rustc: Version) -> bool24     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 
parse(iter: Iter) -> Result<Expr>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 
parse_nightly(iter: Iter) -> Result<Expr>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 
parse_stable(iter: Iter) -> Result<Expr>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 
parse_since(introducer: &Ident, iter: Iter) -> Result<Expr>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 
parse_before(introducer: &Ident, iter: Iter) -> Result<Expr>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 
parse_not(introducer: &Ident, iter: Iter) -> Result<Expr>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 
parse_any(introducer: &Ident, iter: Iter) -> Result<Expr>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 
parse_all(introducer: &Ident, iter: Iter) -> Result<Expr>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 
parse_comma_separated(iter: Iter) -> Result<Vec<Expr>>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 }
164