Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
233
third-party/vendor/paste/src/segment.rs
vendored
Normal file
233
third-party/vendor/paste/src/segment.rs
vendored
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
use crate::error::{Error, Result};
|
||||
use proc_macro::{token_stream, Delimiter, Ident, Span, TokenTree};
|
||||
use std::iter::Peekable;
|
||||
|
||||
pub(crate) enum Segment {
|
||||
String(LitStr),
|
||||
Apostrophe(Span),
|
||||
Env(LitStr),
|
||||
Modifier(Colon, Ident),
|
||||
}
|
||||
|
||||
pub(crate) struct LitStr {
|
||||
pub value: String,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub(crate) struct Colon {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub(crate) fn parse(tokens: &mut Peekable<token_stream::IntoIter>) -> Result<Vec<Segment>> {
|
||||
let mut segments = Vec::new();
|
||||
while match tokens.peek() {
|
||||
None => false,
|
||||
Some(TokenTree::Punct(punct)) => punct.as_char() != '>',
|
||||
Some(_) => true,
|
||||
} {
|
||||
match tokens.next().unwrap() {
|
||||
TokenTree::Ident(ident) => {
|
||||
let mut fragment = ident.to_string();
|
||||
if fragment.starts_with("r#") {
|
||||
fragment = fragment.split_off(2);
|
||||
}
|
||||
if fragment == "env"
|
||||
&& match tokens.peek() {
|
||||
Some(TokenTree::Punct(punct)) => punct.as_char() == '!',
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
let bang = tokens.next().unwrap(); // `!`
|
||||
let expect_group = tokens.next();
|
||||
let parenthesized = match &expect_group {
|
||||
Some(TokenTree::Group(group))
|
||||
if group.delimiter() == Delimiter::Parenthesis =>
|
||||
{
|
||||
group
|
||||
}
|
||||
Some(wrong) => return Err(Error::new(wrong.span(), "expected `(`")),
|
||||
None => {
|
||||
return Err(Error::new2(
|
||||
ident.span(),
|
||||
bang.span(),
|
||||
"expected `(` after `env!`",
|
||||
));
|
||||
}
|
||||
};
|
||||
let mut inner = parenthesized.stream().into_iter();
|
||||
let lit = match inner.next() {
|
||||
Some(TokenTree::Literal(lit)) => lit,
|
||||
Some(wrong) => {
|
||||
return Err(Error::new(wrong.span(), "expected string literal"))
|
||||
}
|
||||
None => {
|
||||
return Err(Error::new2(
|
||||
ident.span(),
|
||||
parenthesized.span(),
|
||||
"expected string literal as argument to env! macro",
|
||||
))
|
||||
}
|
||||
};
|
||||
let lit_string = lit.to_string();
|
||||
if lit_string.starts_with('"')
|
||||
&& lit_string.ends_with('"')
|
||||
&& lit_string.len() >= 2
|
||||
{
|
||||
// TODO: maybe handle escape sequences in the string if
|
||||
// someone has a use case.
|
||||
segments.push(Segment::Env(LitStr {
|
||||
value: lit_string[1..lit_string.len() - 1].to_owned(),
|
||||
span: lit.span(),
|
||||
}));
|
||||
} else {
|
||||
return Err(Error::new(lit.span(), "expected string literal"));
|
||||
}
|
||||
if let Some(unexpected) = inner.next() {
|
||||
return Err(Error::new(
|
||||
unexpected.span(),
|
||||
"unexpected token in env! macro",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
segments.push(Segment::String(LitStr {
|
||||
value: fragment,
|
||||
span: ident.span(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
TokenTree::Literal(lit) => {
|
||||
segments.push(Segment::String(LitStr {
|
||||
value: lit.to_string(),
|
||||
span: lit.span(),
|
||||
}));
|
||||
}
|
||||
TokenTree::Punct(punct) => match punct.as_char() {
|
||||
'_' => segments.push(Segment::String(LitStr {
|
||||
value: "_".to_owned(),
|
||||
span: punct.span(),
|
||||
})),
|
||||
'\'' => segments.push(Segment::Apostrophe(punct.span())),
|
||||
':' => {
|
||||
let colon_span = punct.span();
|
||||
let colon = Colon { span: colon_span };
|
||||
let ident = match tokens.next() {
|
||||
Some(TokenTree::Ident(ident)) => ident,
|
||||
wrong => {
|
||||
let span = wrong.as_ref().map_or(colon_span, TokenTree::span);
|
||||
return Err(Error::new(span, "expected identifier after `:`"));
|
||||
}
|
||||
};
|
||||
segments.push(Segment::Modifier(colon, ident));
|
||||
}
|
||||
_ => return Err(Error::new(punct.span(), "unexpected punct")),
|
||||
},
|
||||
TokenTree::Group(group) => {
|
||||
if group.delimiter() == Delimiter::None {
|
||||
let mut inner = group.stream().into_iter().peekable();
|
||||
let nested = parse(&mut inner)?;
|
||||
if let Some(unexpected) = inner.next() {
|
||||
return Err(Error::new(unexpected.span(), "unexpected token"));
|
||||
}
|
||||
segments.extend(nested);
|
||||
} else {
|
||||
return Err(Error::new(group.span(), "unexpected token"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(segments)
|
||||
}
|
||||
|
||||
pub(crate) fn paste(segments: &[Segment]) -> Result<String> {
|
||||
let mut evaluated = Vec::new();
|
||||
let mut is_lifetime = false;
|
||||
|
||||
for segment in segments {
|
||||
match segment {
|
||||
Segment::String(segment) => {
|
||||
evaluated.push(segment.value.clone());
|
||||
}
|
||||
Segment::Apostrophe(span) => {
|
||||
if is_lifetime {
|
||||
return Err(Error::new(*span, "unexpected lifetime"));
|
||||
}
|
||||
is_lifetime = true;
|
||||
}
|
||||
Segment::Env(var) => {
|
||||
let resolved = match std::env::var(&var.value) {
|
||||
Ok(resolved) => resolved,
|
||||
Err(_) => {
|
||||
return Err(Error::new(
|
||||
var.span,
|
||||
&format!("no such env var: {:?}", var.value),
|
||||
));
|
||||
}
|
||||
};
|
||||
let resolved = resolved.replace('-', "_");
|
||||
evaluated.push(resolved);
|
||||
}
|
||||
Segment::Modifier(colon, ident) => {
|
||||
let last = match evaluated.pop() {
|
||||
Some(last) => last,
|
||||
None => {
|
||||
return Err(Error::new2(colon.span, ident.span(), "unexpected modifier"))
|
||||
}
|
||||
};
|
||||
match ident.to_string().as_str() {
|
||||
"lower" => {
|
||||
evaluated.push(last.to_lowercase());
|
||||
}
|
||||
"upper" => {
|
||||
evaluated.push(last.to_uppercase());
|
||||
}
|
||||
"snake" => {
|
||||
let mut acc = String::new();
|
||||
let mut prev = '_';
|
||||
for ch in last.chars() {
|
||||
if ch.is_uppercase() && prev != '_' {
|
||||
acc.push('_');
|
||||
}
|
||||
acc.push(ch);
|
||||
prev = ch;
|
||||
}
|
||||
evaluated.push(acc.to_lowercase());
|
||||
}
|
||||
"camel" => {
|
||||
let mut acc = String::new();
|
||||
let mut prev = '_';
|
||||
for ch in last.chars() {
|
||||
if ch != '_' {
|
||||
if prev == '_' {
|
||||
for chu in ch.to_uppercase() {
|
||||
acc.push(chu);
|
||||
}
|
||||
} else if prev.is_uppercase() {
|
||||
for chl in ch.to_lowercase() {
|
||||
acc.push(chl);
|
||||
}
|
||||
} else {
|
||||
acc.push(ch);
|
||||
}
|
||||
}
|
||||
prev = ch;
|
||||
}
|
||||
evaluated.push(acc);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::new2(
|
||||
colon.span,
|
||||
ident.span(),
|
||||
"unsupported modifier",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut pasted = evaluated.into_iter().collect::<String>();
|
||||
if is_lifetime {
|
||||
pasted.insert(0, '\'');
|
||||
}
|
||||
Ok(pasted)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue