konst_proc_macros-0.3.10/.cargo_vcs_info.json0000644000000001570000000000100146450ustar { "git": { "sha1": "70ad2209a32e575564cbfb7f381616c33ce6caff" }, "path_in_vcs": "konst_proc_macros" }konst_proc_macros-0.3.10/Cargo.toml0000644000000021360000000000100126420ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.65.0" name = "konst_proc_macros" version = "0.3.10" authors = ["rodrimati1992 "] build = false include = [ "Cargo.toml", "src/**/*.rs", "LICENSE-ZLIB.md", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Implementation detail of the `konst` crate" documentation = "https://docs.rs/konst/" readme = false keywords = ["no-std"] categories = ["no-std"] license = "Zlib" repository = "https://github.com/rodrimati1992/konst/" resolver = "1" [lib] name = "konst_proc_macros" path = "src/lib.rs" proc-macro = true [dependencies] konst_proc_macros-0.3.10/Cargo.toml.orig000064400000000000000000000007471046102023000163310ustar 00000000000000[package] name = "konst_proc_macros" version = "0.3.10" authors = ["rodrimati1992 "] rust-version = "1.65.0" edition = "2021" license = "Zlib" description = "Implementation detail of the `konst` crate" documentation = "https://docs.rs/konst/" keywords = ["no-std"] categories = ["no-std"] repository = "https://github.com/rodrimati1992/konst/" include = [ "Cargo.toml", "src/**/*.rs", "LICENSE-ZLIB.md", ] [dependencies] [lib] proc-macro = true konst_proc_macros-0.3.10/LICENSE-ZLIB.md000064400000000000000000000015271046102023000156010ustar 00000000000000Copyright (c) 2021 Matias Rodriguez. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.konst_proc_macros-0.3.10/src/lib.rs000064400000000000000000000055061046102023000153430ustar 00000000000000#![allow(clippy::or_fun_call)] #![allow(clippy::useless_conversion)] #![allow(irrefutable_let_patterns)] extern crate proc_macro; use proc_macro as used_proc_macro; use std::iter; #[allow(unused_imports)] use used_proc_macro::{ Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, }; mod parsing; mod utils; #[doc(hidden)] #[proc_macro] pub fn __priv_bstr_start(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { bstr_pattern(input_tokens.into(), StrAt::Start).into() } #[doc(hidden)] #[proc_macro] pub fn __priv_bstr_end(input_tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { bstr_pattern(input_tokens.into(), StrAt::End).into() } fn bstr_pattern(input_tokens: TokenStream, str_at: StrAt) -> TokenStream { use crate::utils::punct_token; let parsed = parsing::parse_inputs(input_tokens); match parsed { Ok(Inputs { rem_ident, strings }) => { let mut out = TokenStream::new(); for (i, patt) in strings.iter().enumerate() { let span = patt.span(&rem_ident); if i != 0 { out.extend(punct_token('|', span)); } let tt = crate::utils::bracket(Span::call_site(), |out| match str_at { StrAt::Start => { output_patt(patt, out); output_remainder_pat(&rem_ident, out); } StrAt::End => { output_remainder_pat(&rem_ident, out); out.extend(punct_token(',', span)); output_patt(patt, out); } }); out.extend(iter::once(tt)) } out } Err(e) => e.to_compile_error(), } } fn output_patt(patt: &Pattern, out: &mut TokenStream) { use crate::utils::punct_token; match patt { Pattern::String { string, span } => { for b in string.bytes() { let mut lit = Literal::u8_unsuffixed(b); lit.set_span(*span); out.extend(iter::once(TokenTree::from(lit))); out.extend(punct_token(',', *span)); } } } } fn output_remainder_pat(patt: &Ident, out: &mut TokenStream) { use crate::utils::{punct_joint_token2, punct_token}; out.extend(iter::once(TokenTree::from(patt.clone()))); out.extend(punct_token('@', patt.span())); out.extend(punct_joint_token2('.', '.', patt.span())); } struct Inputs { rem_ident: Ident, strings: Vec, } enum Pattern { String { string: String, span: Span }, } enum StrAt { Start, End, } impl Pattern { fn span(&self, _rem_ident: &Ident) -> Span { match self { Pattern::String { span, .. } => *span, } } } konst_proc_macros-0.3.10/src/parsing.rs000064400000000000000000000174361046102023000162450ustar 00000000000000#[allow(unused_imports)] use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; use proc_macro::token_stream::IntoIter as TSIterator; use crate::{utils::Error, Inputs, Pattern}; pub(crate) fn parse_inputs(ts: TokenStream) -> Result { let iter = &mut ts.into_iter(); let rem_ident = match iter.next() { Some(TokenTree::Ident(ident)) => ident, Some(x) => { return Err(Error::new( x.span(), &format!("Expected identifier.\nFound: {}", x), )); } None => return Err(Error::new(Span::call_site(), "Expected an identifier")), }; assert_punct(iter.next(), ',')?; let mut strings = Vec::::with_capacity(1); while let Some(x) = parse_lstr(iter)? { strings.push(x); match iter.next() { Some(TokenTree::Punct(p)) if p.as_char() == '|' => {} Some(x) => { return Err(Error::new( x.span(), &format!("Expected a `|`\nfound: `{}`", x), )) } None => {} } } Ok(Inputs { rem_ident, strings }) } const IN_MSG: &str = "Expected one of: string literal, concat!(...) , stringify!(...)"; fn parse_lstr(iter: &mut TSIterator) -> Result, Error> { match iter.next() { Some(TokenTree::Ident(ident)) => { let string = ident.to_string(); if string == "concat" { let (span, ts) = parse_post_macro_name(iter)?; let mut string = String::new(); let iter = &mut ts.into_iter(); while let Some(patt) = parse_lstr(iter)? { if let Pattern::String { string: s, .. } = patt { string.push_str(&s); } if let sep @ Some(_) = iter.next() { assert_punct(sep, ',')?; } } Ok(Some(Pattern::String { string, span })) } else if string == "stringify" { let (span, ts) = parse_post_macro_name(iter)?; let string = ts.to_string(); Ok(Some(Pattern::String { string, span })) } else { Err(Error::new( ident.span(), &format!("{}\nFound: {}", IN_MSG, ident), )) } } Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => { parse_lstr(&mut group.stream().into_iter()) } Some(TokenTree::Literal(lit)) => parse_literal(lit).map(Some), Some(x) => Err(Error::new(x.span(), &format!("{}\nFound: {}", IN_MSG, x))), None => Ok(None), } } fn parse_post_macro_name(iter: &mut TSIterator) -> Result<(Span, TokenStream), Error> { let bang_span = assert_punct(iter.next(), '!')?; match iter.next() { Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => { Ok((g.span(), g.stream())) } _ => Err(Error::new(bang_span, "Expected `( ..... )` after `!`")), } } fn parse_literal(lit: Literal) -> Result { let span = lit.span(); let string = lit.to_string(); let string = if string.starts_with('"') { parse_string(&string, span)? } else if string.starts_with('r') { parse_raw_string(&string, span)? } else { return Err(Error::new(span, &format!("{}\nFound: {}", IN_MSG, lit))); }; Ok(Pattern::String { string, span }) } fn parse_string(input: &str, span: Span) -> Result { if !input.ends_with('"') { return Err(Error::new( span, "Somehow there's no terminating quote character?", )); } let make_err = |rem: &str, error: &str| -> Error { let pos = rem.as_ptr() as usize - input.as_ptr() as usize; let upto = input[..pos] .chars() .rev() .take(10) .collect::() .chars() .rev() .collect::(); Error::new(span, &format!("Error: {} After: {}", error, upto,)) }; let mut rem = &input[1..input.len() - 1]; let mut out = String::new(); loop { let end_copied = rem.find('\\').unwrap_or(rem.len()); out.push_str(&rem[..end_copied]); rem = &rem[end_copied..]; if rem.is_empty() { break; } // The byte after the '\\' character let b = get_byte(rem, 1); // Now we're at the character right after the matched one. rem = &rem[2..]; out.push(match b { b'x' => { if let Some(hex) = rem.get(..2) { let num = u8::from_str_radix(hex, 16) .ok() .filter(|&x| x < 128) .ok_or_else(|| { make_err( rem, &format!("expected values from \\x00 to \\x7F, found: {}", hex), ) })?; out.push(num as char); } else { return Err(make_err(rem, "invalid ascii escape")); } rem = &rem[2..]; continue; } b'u' => { if let Some(end_brace) = rem.bytes().position(|b| b == b'}') { let c: char = u32::from_str_radix(&rem[1..end_brace], 16) .ok() .and_then(std::char::from_u32) .ok_or_else(|| { make_err( rem, &format!("Invalid unicode escape: {}", &rem[..end_brace]), ) })?; out.push(c); rem = &rem[end_brace + 1..]; } else { return Err(make_err(rem, "Expected closing brace for unicode escape")); } continue; } b'n' => '\n', b'r' => '\r', b't' => '\t', b'\\' => '\\', b'0' => '\0', b'\'' => '\'', b'"' => '"', b'\r' | b'\n' => { rem = rem.trim_start(); continue; } _ => return Err(make_err(rem, "invalid escape")), }); } Ok(out) } fn get_byte(s: &str, at: usize) -> u8 { match s.as_bytes().get(at) { Some(&x) => x, None => 0, } } fn parse_raw_string(input: &str, span: Span) -> Result { let input = &input[1..]; let hash_count = input .bytes() .position(|b| b != b'#') .filter(|&p| input.as_bytes()[p] == b'"') .ok_or_else(|| { Error::new( span, "Couldn't find initial '\"' character in raw string literal.", ) })?; let end_quote = input .bytes() .rev() .position(|b| b != b'#') .map(|p| input.len() - 1 - p) .filter(|&p| input.as_bytes()[p] == b'"') .ok_or_else(|| { Error::new( span, "Couldn't find final '\"' character in raw string literal.", ) })?; Ok(input[hash_count + 1..end_quote].to_string()) } fn assert_punct(tt: Option, c: char) -> Result { match tt { Some(TokenTree::Punct(p)) if p.as_char() == c => Ok(p.span()), Some(x) => Err(Error::new( x.span(), &format!("Expected `{}`, found `{}`", c, x), )), None => Err(Error::new(Span::call_site(), "Expected some token")), } } konst_proc_macros-0.3.10/src/utils.rs000064400000000000000000000065621046102023000157400ustar 00000000000000use std::iter::{self, Once}; #[allow(unused_imports)] use crate::used_proc_macro::{ Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, }; pub(crate) fn ident_token(ident: &str, span: Span) -> Once { let ident = Ident::new(ident, span); let tt = TokenTree::from(ident); iter::once(tt) } pub(crate) fn punct_token(token: char, span: Span) -> Once { let mut token = Punct::new(token, Spacing::Alone); token.set_span(span); let tt = TokenTree::from(token); iter::once(tt) } pub(crate) fn punct_joint_token2(first: char, second: char, span: Span) -> Vec { let tt_first = { let mut token = Punct::new(first, Spacing::Joint); token.set_span(span); TokenTree::from(token) }; let tt_second = { let mut token = Punct::new(second, Spacing::Alone); token.set_span(span); TokenTree::from(token) }; vec![tt_first, tt_second] } pub(crate) fn paren(span: Span, f: F) -> TokenTree where F: FnOnce(&mut TokenStream), { let mut ts = TokenStream::new(); f(&mut ts); let mut tt = Group::new(Delimiter::Parenthesis, ts); tt.set_span(span); TokenTree::from(tt) } pub(crate) fn bracket(span: Span, f: F) -> TokenTree where F: FnOnce(&mut TokenStream), { let mut ts = TokenStream::new(); f(&mut ts); let mut tt = Group::new(Delimiter::Bracket, ts); tt.set_span(span); TokenTree::from(tt) } /////////////////////////////////////////////////////// pub(crate) struct Error { span: Span, message: String, } impl Error { pub(crate) fn new(span: Span, message: &str) -> Self { Self { span, message: message.to_string(), } } pub(crate) fn to_compile_error(&self) -> TokenStream { let Error { ref message, span } = *self; let mut out = TokenStream::new(); out.extend(crate::utils::ident_token("compile_error", span)); out.extend(crate::utils::punct_token('!', span)); let msg_paren = crate::utils::paren(span, |ts| { let mut msg = Literal::string(message); msg.set_span(self.span); let msg = TokenTree::from(msg); ts.extend(iter::once(msg)) }); out.extend(iter::once(msg_paren)); out } } /////////////////////////////////////////////////////// #[allow(dead_code)] pub(crate) trait TokenTreeExt: Sized { fn into_token_tree(self) -> TokenTree; fn set_span_recursive(self, span: Span) -> TokenTree { let mut tt = self.into_token_tree(); tt.set_span(span); if let TokenTree::Group(group) = tt { let delim = group.delimiter(); let stream = group.stream().set_span_recursive(span); tt = TokenTree::Group(Group::new(delim, stream)); } tt.set_span(span); tt } } impl TokenTreeExt for TokenTree { fn into_token_tree(self) -> TokenTree { self } } #[allow(dead_code)] pub trait TokenStreamExt: Sized { fn into_token_stream(self) -> TokenStream; fn set_span_recursive(self, span: Span) -> TokenStream { self.into_token_stream() .into_iter() .map(|tt| tt.set_span_recursive(span)) .collect() } } impl TokenStreamExt for TokenStream { fn into_token_stream(self) -> TokenStream { self } }