1#![doc(html_root_url = "https://docs.rs/macro-string/0.2.0")]
70
71use proc_macro2::TokenStream;
72use quote::{quote, ToTokens};
73use std::env;
74use std::fmt::Display;
75use std::fs;
76use std::path::{Component, Path, PathBuf};
77use syn::parse::{Error, Parse, ParseBuffer, ParseStream, Parser, Result};
78use syn::punctuated::Punctuated;
79use syn::token::{Brace, Bracket, Paren};
80use syn::{
81 braced, bracketed, parenthesized, Ident, LitBool, LitChar, LitFloat, LitInt, LitStr, Token,
82};
83
84mod kw {
85 #[allow(non_camel_case_types)]
pub struct concat {
#[allow(dead_code)]
pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn concat<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
__S) -> concat {
concat { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
{
impl ::syn::__private::Default for concat {
fn default() -> Self {
concat { span: ::syn::__private::Span::call_site() }
}
}
impl ::syn::__private::CustomToken for concat {
fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
{
ident == "concat"
} else { false }
}
fn display() -> &'static ::syn::__private::str { "`concat`" }
}
impl ::syn::parse::Parse for concat {
fn parse(input: ::syn::parse::ParseStream)
-> ::syn::parse::Result<concat> {
input.step(|cursor|
{
if let ::syn::__private::Some((ident, rest)) =
cursor.ident() {
if ident == "concat" {
return ::syn::__private::Ok((concat { span: ident.span() },
rest));
}
}
::syn::__private::Err(cursor.error("expected `concat`"))
})
}
}
impl ::syn::__private::ToTokens for concat {
fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
let ident = ::syn::Ident::new("concat", self.span);
::syn::__private::TokenStreamExt::append(tokens, ident);
}
}
impl ::syn::__private::Copy for concat {}
#[allow(clippy :: expl_impl_clone_on_copy)]
impl ::syn::__private::Clone for concat {
fn clone(&self) -> Self { *self }
}
;
};syn::custom_keyword!(concat);
86 #[allow(non_camel_case_types)]
pub struct env {
#[allow(dead_code)]
pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn env<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
__S) -> env {
env { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
{
impl ::syn::__private::Default for env {
fn default() -> Self {
env { span: ::syn::__private::Span::call_site() }
}
}
impl ::syn::__private::CustomToken for env {
fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
{
ident == "env"
} else { false }
}
fn display() -> &'static ::syn::__private::str { "`env`" }
}
impl ::syn::parse::Parse for env {
fn parse(input: ::syn::parse::ParseStream)
-> ::syn::parse::Result<env> {
input.step(|cursor|
{
if let ::syn::__private::Some((ident, rest)) =
cursor.ident() {
if ident == "env" {
return ::syn::__private::Ok((env { span: ident.span() },
rest));
}
}
::syn::__private::Err(cursor.error("expected `env`"))
})
}
}
impl ::syn::__private::ToTokens for env {
fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
let ident = ::syn::Ident::new("env", self.span);
::syn::__private::TokenStreamExt::append(tokens, ident);
}
}
impl ::syn::__private::Copy for env {}
#[allow(clippy :: expl_impl_clone_on_copy)]
impl ::syn::__private::Clone for env {
fn clone(&self) -> Self { *self }
}
;
};syn::custom_keyword!(env);
87 #[allow(non_camel_case_types)]
pub struct include {
#[allow(dead_code)]
pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn include<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
__S) -> include {
include { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
{
impl ::syn::__private::Default for include {
fn default() -> Self {
include { span: ::syn::__private::Span::call_site() }
}
}
impl ::syn::__private::CustomToken for include {
fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
{
ident == "include"
} else { false }
}
fn display() -> &'static ::syn::__private::str { "`include`" }
}
impl ::syn::parse::Parse for include {
fn parse(input: ::syn::parse::ParseStream)
-> ::syn::parse::Result<include> {
input.step(|cursor|
{
if let ::syn::__private::Some((ident, rest)) =
cursor.ident() {
if ident == "include" {
return ::syn::__private::Ok((include { span: ident.span() },
rest));
}
}
::syn::__private::Err(cursor.error("expected `include`"))
})
}
}
impl ::syn::__private::ToTokens for include {
fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
let ident = ::syn::Ident::new("include", self.span);
::syn::__private::TokenStreamExt::append(tokens, ident);
}
}
impl ::syn::__private::Copy for include {}
#[allow(clippy :: expl_impl_clone_on_copy)]
impl ::syn::__private::Clone for include {
fn clone(&self) -> Self { *self }
}
;
};syn::custom_keyword!(include);
88 #[allow(non_camel_case_types)]
pub struct include_str {
#[allow(dead_code)]
pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn include_str<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
__S) -> include_str {
include_str { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
{
impl ::syn::__private::Default for include_str {
fn default() -> Self {
include_str { span: ::syn::__private::Span::call_site() }
}
}
impl ::syn::__private::CustomToken for include_str {
fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
{
ident == "include_str"
} else { false }
}
fn display() -> &'static ::syn::__private::str { "`include_str`" }
}
impl ::syn::parse::Parse for include_str {
fn parse(input: ::syn::parse::ParseStream)
-> ::syn::parse::Result<include_str> {
input.step(|cursor|
{
if let ::syn::__private::Some((ident, rest)) =
cursor.ident() {
if ident == "include_str" {
return ::syn::__private::Ok((include_str {
span: ident.span(),
}, rest));
}
}
::syn::__private::Err(cursor.error("expected `include_str`"))
})
}
}
impl ::syn::__private::ToTokens for include_str {
fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
let ident = ::syn::Ident::new("include_str", self.span);
::syn::__private::TokenStreamExt::append(tokens, ident);
}
}
impl ::syn::__private::Copy for include_str {}
#[allow(clippy :: expl_impl_clone_on_copy)]
impl ::syn::__private::Clone for include_str {
fn clone(&self) -> Self { *self }
}
;
};syn::custom_keyword!(include_str);
89 #[allow(non_camel_case_types)]
pub struct stringify {
#[allow(dead_code)]
pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn stringify<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
__S) -> stringify {
stringify { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
{
impl ::syn::__private::Default for stringify {
fn default() -> Self {
stringify { span: ::syn::__private::Span::call_site() }
}
}
impl ::syn::__private::CustomToken for stringify {
fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
{
ident == "stringify"
} else { false }
}
fn display() -> &'static ::syn::__private::str { "`stringify`" }
}
impl ::syn::parse::Parse for stringify {
fn parse(input: ::syn::parse::ParseStream)
-> ::syn::parse::Result<stringify> {
input.step(|cursor|
{
if let ::syn::__private::Some((ident, rest)) =
cursor.ident() {
if ident == "stringify" {
return ::syn::__private::Ok((stringify {
span: ident.span(),
}, rest));
}
}
::syn::__private::Err(cursor.error("expected `stringify`"))
})
}
}
impl ::syn::__private::ToTokens for stringify {
fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
let ident = ::syn::Ident::new("stringify", self.span);
::syn::__private::TokenStreamExt::append(tokens, ident);
}
}
impl ::syn::__private::Copy for stringify {}
#[allow(clippy :: expl_impl_clone_on_copy)]
impl ::syn::__private::Clone for stringify {
fn clone(&self) -> Self { *self }
}
;
};syn::custom_keyword!(stringify);
90}
91
92#[derive(#[automatically_derived]
impl ::core::clone::Clone for MacroString {
#[inline]
fn clone(&self) -> MacroString {
MacroString { expr: ::core::clone::Clone::clone(&self.expr) }
}
}Clone)]
93pub struct MacroString {
94 expr: Expr,
95}
96
97impl Parse for MacroString {
98 fn parse(input: ParseStream) -> Result<Self> {
99 Ok(MacroString {
100 expr: input.call(Expr::parse_strict)?,
101 })
102 }
103}
104
105impl MacroString {
106 pub fn eval(&self) -> Result<String> {
115 self.expr.eval()
116 }
117
118 pub fn error<T: Display>(&self, message: T) -> syn::Error {
135 syn::Error::new_spanned(&self.expr, message)
136 }
137}
138
139#[derive(#[automatically_derived]
impl ::core::clone::Clone for Expr {
#[inline]
fn clone(&self) -> Expr {
match self {
Expr::LitStr(__self_0) =>
Expr::LitStr(::core::clone::Clone::clone(__self_0)),
Expr::LitChar(__self_0) =>
Expr::LitChar(::core::clone::Clone::clone(__self_0)),
Expr::LitInt(__self_0) =>
Expr::LitInt(::core::clone::Clone::clone(__self_0)),
Expr::LitFloat(__self_0) =>
Expr::LitFloat(::core::clone::Clone::clone(__self_0)),
Expr::LitBool(__self_0) =>
Expr::LitBool(::core::clone::Clone::clone(__self_0)),
Expr::Concat(__self_0) =>
Expr::Concat(::core::clone::Clone::clone(__self_0)),
Expr::Env(__self_0) =>
Expr::Env(::core::clone::Clone::clone(__self_0)),
Expr::Include(__self_0) =>
Expr::Include(::core::clone::Clone::clone(__self_0)),
Expr::IncludeStr(__self_0) =>
Expr::IncludeStr(::core::clone::Clone::clone(__self_0)),
Expr::Stringify(__self_0) =>
Expr::Stringify(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
140enum Expr {
141 LitStr(LitStr),
142 LitChar(LitChar),
143 LitInt(LitInt),
144 LitFloat(LitFloat),
145 LitBool(LitBool),
146 Concat(Concat),
147 Env(Env),
148 Include(Include),
149 IncludeStr(IncludeStr),
150 Stringify(Stringify),
151}
152
153impl Expr {
154 fn eval(&self) -> Result<String> {
155 match self {
156 Expr::LitStr(lit) => Ok(lit.value()),
157 Expr::LitChar(lit) => Ok(lit.value().to_string()),
158 Expr::LitInt(lit) => Ok(lit.base10_digits().to_owned()),
159 Expr::LitFloat(lit) => Ok(lit.base10_digits().to_owned()),
160 Expr::LitBool(lit) => Ok(lit.value.to_string()),
161 Expr::Concat(expr) => {
162 let mut concat = String::new();
163 for arg in &expr.args {
164 concat += &arg.eval()?;
165 }
166 Ok(concat)
167 }
168 Expr::Env(expr) => {
169 let key = expr.arg.eval()?;
170 match env::var(&key) {
171 Ok(value) => Ok(value),
172 Err(err) => Err(Error::new_spanned(expr, err)),
173 }
174 }
175 Expr::Include(expr) => {
176 let path = expr.arg.eval()?;
177 let content = fs_read(&expr, &path)?;
178 let inner = Expr::parse_strict.parse_str(&content)?;
179 inner.eval()
180 }
181 Expr::IncludeStr(expr) => {
182 let path = expr.arg.eval()?;
183 fs_read(&expr, &path)
184 }
185 Expr::Stringify(expr) => Ok(expr.tokens.to_string()),
186 }
187 }
188}
189
190fn fs_read(span: &dyn ToTokens, path: impl AsRef<Path>) -> Result<String> {
191 let mut path = path.as_ref();
192 if path.is_relative() {
193 let name = span.to_token_stream().into_iter().next().unwrap();
194 return Err(Error::new_spanned(
195 span,
196 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a relative path is not supported here; use `{0}!(concat!(env!(\"CARGO_MANIFEST_DIR\"), ...))`",
name))
})format!("a relative path is not supported here; use `{name}!(concat!(env!(\"CARGO_MANIFEST_DIR\"), ...))`"),
197 ));
198 }
199
200 let path_buf: PathBuf;
203 if let Some(Component::Prefix(prefix)) = path.components().next() {
204 if prefix.kind().is_verbatim() {
205 path_buf = path.components().collect();
206 path = &path_buf;
207 }
208 }
209
210 match fs::read_to_string(path) {
211 Ok(content) => Ok(content),
212 Err(err) => Err(Error::new_spanned(
213 span,
214 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} {1}", err, path.display()))
})format!("{} {}", err, path.display()),
215 )),
216 }
217}
218
219#[derive(#[automatically_derived]
impl ::core::clone::Clone for Concat {
#[inline]
fn clone(&self) -> Concat {
Concat {
name: ::core::clone::Clone::clone(&self.name),
bang_token: ::core::clone::Clone::clone(&self.bang_token),
delimiter: ::core::clone::Clone::clone(&self.delimiter),
args: ::core::clone::Clone::clone(&self.args),
}
}
}Clone)]
220struct Concat {
221 name: kw::concat,
222 bang_token: ::syn::token::NotToken![!],
223 delimiter: MacroDelimiter,
224 args: Punctuated<Expr, ::syn::token::CommaToken![,]>,
225}
226
227#[derive(#[automatically_derived]
impl ::core::clone::Clone for Env {
#[inline]
fn clone(&self) -> Env {
Env {
name: ::core::clone::Clone::clone(&self.name),
bang_token: ::core::clone::Clone::clone(&self.bang_token),
delimiter: ::core::clone::Clone::clone(&self.delimiter),
arg: ::core::clone::Clone::clone(&self.arg),
trailing_comma: ::core::clone::Clone::clone(&self.trailing_comma),
}
}
}Clone)]
228struct Env {
229 name: kw::env,
230 bang_token: ::syn::token::NotToken![!],
231 delimiter: MacroDelimiter,
232 arg: Box<Expr>,
233 trailing_comma: Option<::syn::token::CommaToken![,]>,
234}
235
236#[derive(#[automatically_derived]
impl ::core::clone::Clone for Include {
#[inline]
fn clone(&self) -> Include {
Include {
name: ::core::clone::Clone::clone(&self.name),
bang_token: ::core::clone::Clone::clone(&self.bang_token),
delimiter: ::core::clone::Clone::clone(&self.delimiter),
arg: ::core::clone::Clone::clone(&self.arg),
trailing_comma: ::core::clone::Clone::clone(&self.trailing_comma),
}
}
}Clone)]
237struct Include {
238 name: kw::include,
239 bang_token: ::syn::token::NotToken![!],
240 delimiter: MacroDelimiter,
241 arg: Box<Expr>,
242 trailing_comma: Option<::syn::token::CommaToken![,]>,
243}
244
245#[derive(#[automatically_derived]
impl ::core::clone::Clone for IncludeStr {
#[inline]
fn clone(&self) -> IncludeStr {
IncludeStr {
name: ::core::clone::Clone::clone(&self.name),
bang_token: ::core::clone::Clone::clone(&self.bang_token),
delimiter: ::core::clone::Clone::clone(&self.delimiter),
arg: ::core::clone::Clone::clone(&self.arg),
trailing_comma: ::core::clone::Clone::clone(&self.trailing_comma),
}
}
}Clone)]
246struct IncludeStr {
247 name: kw::include_str,
248 bang_token: ::syn::token::NotToken![!],
249 delimiter: MacroDelimiter,
250 arg: Box<Expr>,
251 trailing_comma: Option<::syn::token::CommaToken![,]>,
252}
253
254#[derive(#[automatically_derived]
impl ::core::clone::Clone for Stringify {
#[inline]
fn clone(&self) -> Stringify {
Stringify {
name: ::core::clone::Clone::clone(&self.name),
bang_token: ::core::clone::Clone::clone(&self.bang_token),
delimiter: ::core::clone::Clone::clone(&self.delimiter),
tokens: ::core::clone::Clone::clone(&self.tokens),
}
}
}Clone)]
255struct Stringify {
256 name: kw::stringify,
257 bang_token: ::syn::token::NotToken![!],
258 delimiter: MacroDelimiter,
259 tokens: TokenStream,
260}
261
262#[derive(#[automatically_derived]
impl ::core::clone::Clone for MacroDelimiter {
#[inline]
fn clone(&self) -> MacroDelimiter {
match self {
MacroDelimiter::Paren(__self_0) =>
MacroDelimiter::Paren(::core::clone::Clone::clone(__self_0)),
MacroDelimiter::Brace(__self_0) =>
MacroDelimiter::Brace(::core::clone::Clone::clone(__self_0)),
MacroDelimiter::Bracket(__self_0) =>
MacroDelimiter::Bracket(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
263enum MacroDelimiter {
264 Paren(Paren),
265 Brace(Brace),
266 Bracket(Bracket),
267}
268
269impl Expr {
270 fn parse_strict(input: ParseStream) -> Result<Self> {
271 Self::parse(input, false)
272 }
273
274 fn parse_any(input: ParseStream) -> Result<Self> {
275 Self::parse(input, true)
276 }
277
278 fn parse(input: ParseStream, allow_nonstring_literals: bool) -> Result<Self> {
279 let lookahead = input.lookahead1();
280 if lookahead.peek(LitStr) {
281 let lit: LitStr = input.parse()?;
282 if !lit.suffix().is_empty() {
283 return Err(Error::new(
284 lit.span(),
285 "unexpected suffix on string literal",
286 ));
287 }
288 Ok(Expr::LitStr(lit))
289 } else if allow_nonstring_literals && input.peek(LitChar) {
290 let lit: LitChar = input.parse()?;
291 if !lit.suffix().is_empty() {
292 return Err(Error::new(lit.span(), "unexpected suffix on char literal"));
293 }
294 Ok(Expr::LitChar(lit))
295 } else if allow_nonstring_literals && input.peek(LitInt) {
296 let lit: LitInt = input.parse()?;
297 match lit.suffix() {
298 "" | "i8" | "i16" | "i32" | "i64" | "i128" | "u8" | "u16" | "u32" | "u64"
299 | "u128" | "f16" | "f32" | "f64" | "f128" => {}
300 _ => {
301 return Err(Error::new(
302 lit.span(),
303 "unexpected suffix on integer literal",
304 ));
305 }
306 }
307 Ok(Expr::LitInt(lit))
308 } else if allow_nonstring_literals && input.peek(LitFloat) {
309 let lit: LitFloat = input.parse()?;
310 match lit.suffix() {
311 "" | "f16" | "f32" | "f64" | "f128" => {}
312 _ => return Err(Error::new(lit.span(), "unexpected suffix on float literal")),
313 }
314 Ok(Expr::LitFloat(lit))
315 } else if allow_nonstring_literals && input.peek(LitBool) {
316 input.parse().map(Expr::LitBool)
317 } else if lookahead.peek(kw::concat) {
318 input.parse().map(Expr::Concat)
319 } else if lookahead.peek(kw::env) {
320 input.parse().map(Expr::Env)
321 } else if lookahead.peek(kw::include) {
322 input.parse().map(Expr::Include)
323 } else if lookahead.peek(kw::include_str) {
324 input.parse().map(Expr::IncludeStr)
325 } else if lookahead.peek(kw::stringify) {
326 input.parse().map(Expr::Stringify)
327 } else if input.peek(Ident) && input.peek2(::syn::token::NotToken![!]) && input.peek3(Paren) {
328 let ident: Ident = input.parse()?;
329 let bang_token: ::syn::token::NotToken![!] = input.parse()?;
330 let unsupported = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ident, &mut _s);
::quote::ToTokens::to_tokens(&bang_token, &mut _s);
_s
}quote!(#ident #bang_token);
331 Err(Error::new_spanned(
332 unsupported,
333 "unsupported macro, expected one of: `concat!`, `env!`, `include!`, `include_str!`, `stringify!`",
334 ))
335 } else {
336 Err(lookahead.error())
337 }
338 }
339}
340
341impl ToTokens for Expr {
342 fn to_tokens(&self, tokens: &mut TokenStream) {
343 match self {
344 Expr::LitStr(expr) => expr.to_tokens(tokens),
345 Expr::LitChar(expr) => expr.to_tokens(tokens),
346 Expr::LitInt(expr) => expr.to_tokens(tokens),
347 Expr::LitFloat(expr) => expr.to_tokens(tokens),
348 Expr::LitBool(expr) => expr.to_tokens(tokens),
349 Expr::Concat(expr) => expr.to_tokens(tokens),
350 Expr::Env(expr) => expr.to_tokens(tokens),
351 Expr::Include(expr) => expr.to_tokens(tokens),
352 Expr::IncludeStr(expr) => expr.to_tokens(tokens),
353 Expr::Stringify(expr) => expr.to_tokens(tokens),
354 }
355 }
356}
357
358macro_rules! macro_delimiter {
359 ($var:ident in $input:ident) => {{
360 let (delim, content) = $input.call(macro_delimiter)?;
361 $var = content;
362 delim
363 }};
364}
365
366fn macro_delimiter(input: ParseStream) -> Result<(MacroDelimiter, ParseBuffer)> {
367 let content;
368 let lookahead = input.lookahead1();
369 let delim = if input.peek(Paren) {
370 MacroDelimiter::Paren(match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => {
content = parens.content;
_ = content;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}parenthesized!(content in input))
371 } else if input.peek(Brace) {
372 MacroDelimiter::Brace(match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => {
content = braces.content;
_ = content;
braces.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}braced!(content in input))
373 } else if input.peek(Bracket) {
374 MacroDelimiter::Bracket(match ::syn::__private::parse_brackets(&input) {
::syn::__private::Ok(brackets) => {
content = brackets.content;
_ = content;
brackets.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}bracketed!(content in input))
375 } else {
376 return Err(lookahead.error());
377 };
378 Ok((delim, content))
379}
380
381impl MacroDelimiter {
382 fn surround<F>(&self, tokens: &mut TokenStream, f: F)
383 where
384 F: FnOnce(&mut TokenStream),
385 {
386 match self {
387 MacroDelimiter::Paren(delimiter) => delimiter.surround(tokens, f),
388 MacroDelimiter::Brace(delimiter) => delimiter.surround(tokens, f),
389 MacroDelimiter::Bracket(delimiter) => delimiter.surround(tokens, f),
390 }
391 }
392}
393
394impl Parse for Concat {
395 fn parse(input: ParseStream) -> Result<Self> {
396 let content;
397 Ok(Concat {
398 name: input.parse()?,
399 bang_token: input.parse()?,
400 delimiter: {
let (delim, content) = input.call(macro_delimiter)?;
content = content;
delim
}macro_delimiter!(content in input),
401 args: Punctuated::parse_terminated_with(&content, Expr::parse_any)?,
402 })
403 }
404}
405
406impl ToTokens for Concat {
407 fn to_tokens(&self, tokens: &mut TokenStream) {
408 self.name.to_tokens(tokens);
409 self.bang_token.to_tokens(tokens);
410 self.delimiter
411 .surround(tokens, |tokens| self.args.to_tokens(tokens));
412 }
413}
414
415impl Parse for Env {
416 fn parse(input: ParseStream) -> Result<Self> {
417 let content;
418 Ok(Env {
419 name: input.parse()?,
420 bang_token: input.parse()?,
421 delimiter: {
let (delim, content) = input.call(macro_delimiter)?;
content = content;
delim
}macro_delimiter!(content in input),
422 arg: Expr::parse_strict(&content).map(Box::new)?,
423 trailing_comma: content.parse()?,
424 })
425 }
426}
427
428impl ToTokens for Env {
429 fn to_tokens(&self, tokens: &mut TokenStream) {
430 self.name.to_tokens(tokens);
431 self.bang_token.to_tokens(tokens);
432 self.delimiter.surround(tokens, |tokens| {
433 self.arg.to_tokens(tokens);
434 self.trailing_comma.to_tokens(tokens);
435 });
436 }
437}
438
439impl Parse for Include {
440 fn parse(input: ParseStream) -> Result<Self> {
441 let content;
442 Ok(Include {
443 name: input.parse()?,
444 bang_token: input.parse()?,
445 delimiter: {
let (delim, content) = input.call(macro_delimiter)?;
content = content;
delim
}macro_delimiter!(content in input),
446 arg: Expr::parse_strict(&content).map(Box::new)?,
447 trailing_comma: content.parse()?,
448 })
449 }
450}
451
452impl ToTokens for Include {
453 fn to_tokens(&self, tokens: &mut TokenStream) {
454 self.name.to_tokens(tokens);
455 self.bang_token.to_tokens(tokens);
456 self.delimiter.surround(tokens, |tokens| {
457 self.arg.to_tokens(tokens);
458 self.trailing_comma.to_tokens(tokens);
459 });
460 }
461}
462
463impl Parse for IncludeStr {
464 fn parse(input: ParseStream) -> Result<Self> {
465 let content;
466 Ok(IncludeStr {
467 name: input.parse()?,
468 bang_token: input.parse()?,
469 delimiter: {
let (delim, content) = input.call(macro_delimiter)?;
content = content;
delim
}macro_delimiter!(content in input),
470 arg: Expr::parse_strict(&content).map(Box::new)?,
471 trailing_comma: content.parse()?,
472 })
473 }
474}
475
476impl ToTokens for IncludeStr {
477 fn to_tokens(&self, tokens: &mut TokenStream) {
478 self.name.to_tokens(tokens);
479 self.bang_token.to_tokens(tokens);
480 self.delimiter.surround(tokens, |tokens| {
481 self.arg.to_tokens(tokens);
482 self.trailing_comma.to_tokens(tokens);
483 });
484 }
485}
486
487impl Parse for Stringify {
488 fn parse(input: ParseStream) -> Result<Self> {
489 let content;
490 Ok(Stringify {
491 name: input.parse()?,
492 bang_token: input.parse()?,
493 delimiter: {
let (delim, content) = input.call(macro_delimiter)?;
content = content;
delim
}macro_delimiter!(content in input),
494 tokens: content.parse()?,
495 })
496 }
497}
498
499impl ToTokens for Stringify {
500 fn to_tokens(&self, tokens: &mut TokenStream) {
501 self.name.to_tokens(tokens);
502 self.bang_token.to_tokens(tokens);
503 self.delimiter
504 .surround(tokens, |tokens| self.tokens.to_tokens(tokens));
505 }
506}