Make tt generic over the span data

This commit is contained in:
Lukas Wirth 2023-01-31 11:49:49 +01:00
parent d805c74c51
commit 41a46a78f2
48 changed files with 806 additions and 569 deletions

View file

@ -8,13 +8,13 @@ use intern::Interned;
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
use smallvec::{smallvec, SmallVec};
use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode};
use tt::Subtree;
use crate::{
db::AstDatabase,
hygiene::Hygiene,
mod_path::{ModPath, PathKind},
name::AsName,
tt::{self, Subtree},
InFile,
};
@ -117,7 +117,10 @@ impl RawAttrs {
let index = attr.id;
let attrs =
parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| {
let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
let tree = Subtree {
delimiter: tt::Delimiter::unspecified(),
token_trees: attr.to_vec(),
};
// FIXME hygiene
let hygiene = Hygiene::new_unhygienic();
Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx))
@ -266,7 +269,7 @@ impl Attr {
pub fn parse_path_comma_token_tree(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
let args = self.token_tree_value()?;
if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
if args.delimiter.kind != DelimiterKind::Parenthesis {
return None;
}
let paths = args

View file

@ -1,6 +1,6 @@
//! Builtin attributes.
use crate::{db::AstDatabase, name, ExpandResult, MacroCallId, MacroCallKind};
use crate::{db::AstDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind};
macro_rules! register_builtin {
( $(($name:ident, $variant:ident) => $expand:ident),* ) => {
@ -97,7 +97,7 @@ fn derive_attr_expand(
let loc = db.lookup_intern_macro_call(id);
let derives = match &loc.kind {
MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0,
_ => return ExpandResult::ok(Default::default()),
_ => return ExpandResult::ok(tt::Subtree::empty()),
};
pseudo_derive_attr_expansion(tt, derives)
}
@ -110,7 +110,7 @@ pub fn pseudo_derive_attr_expansion(
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char,
spacing: tt::Spacing::Alone,
id: tt::TokenId::unspecified(),
span: tt::TokenId::unspecified(),
}))
};

View file

@ -3,11 +3,11 @@
use base_db::{CrateOrigin, LangCrateOrigin};
use tracing::debug;
use crate::tt::{self, TokenId};
use syntax::{
ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName},
match_ast,
};
use tt::TokenId;
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
@ -92,7 +92,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
})?;
let name_token_id =
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
let name_token = tt::Ident { span: name_token_id, text: name.text().into() };
let param_types = params
.into_iter()
.flat_map(|param_list| param_list.type_or_const_params())
@ -101,7 +101,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
let ty = param
.ty()
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
.unwrap_or_default();
.unwrap_or_else(tt::Subtree::empty);
Some(ty)
} else {
None
@ -114,7 +114,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
let info = match parse_adt(tt) {
Ok(info) => info,
Err(e) => return ExpandResult::only_err(e),
Err(e) => return ExpandResult::with_err(tt::Subtree::empty(), e),
};
let (params, args): (Vec<_>, Vec<_>) = info
.param_types
@ -122,7 +122,7 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
.enumerate()
.map(|(idx, param_ty)| {
let ident = tt::Leaf::Ident(tt::Ident {
id: tt::TokenId::unspecified(),
span: tt::TokenId::unspecified(),
text: format!("T{idx}").into(),
});
let ident_ = ident.clone();

View file

@ -9,7 +9,9 @@ use syntax::{
SmolStr,
};
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId, MacroCallLoc};
use crate::{
db::AstDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc,
};
macro_rules! register_builtin {
( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
@ -61,7 +63,7 @@ macro_rules! register_builtin {
};
}
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct ExpandedEager {
pub(crate) subtree: tt::Subtree,
/// The included file ID of the include macro.
@ -116,7 +118,7 @@ register_builtin! {
}
const DOLLAR_CRATE: tt::Ident =
tt::Ident { text: SmolStr::new_inline("$crate"), id: tt::TokenId::unspecified() };
tt::Ident { text: SmolStr::new_inline("$crate"), span: tt::TokenId::unspecified() };
fn module_path_expand(
_db: &dyn AstDatabase,
@ -162,7 +164,7 @@ fn stringify_expand(
_id: MacroCallId,
tt: &tt::Subtree,
) -> ExpandResult<tt::Subtree> {
let pretty = tt::pretty(&tt.token_trees);
let pretty = ::tt::pretty(&tt.token_trees);
let expanded = quote! {
#pretty
@ -194,11 +196,11 @@ fn assert_expand(
let expanded = match &*args {
[cond, panic_args @ ..] => {
let comma = tt::Subtree {
delimiter: None,
delimiter: tt::Delimiter::unspecified(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char: ',',
spacing: tt::Spacing::Alone,
id: tt::TokenId::unspecified(),
span: tt::TokenId::unspecified(),
}))],
};
let cond = cond.clone();
@ -247,7 +249,10 @@ fn format_args_expand(
let mut args = parse_exprs_with_sep(tt, ',');
if args.is_empty() {
return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule.into());
return ExpandResult::with_err(
tt::Subtree::empty(),
mbe::ExpandError::NoMatchingRule.into(),
);
}
for arg in &mut args {
// Remove `key =`.
@ -282,7 +287,7 @@ fn asm_expand(
for tt in tt.token_trees.chunks(2) {
match tt {
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', id: _, spacing: _ }))] =>
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
{
let krate = DOLLAR_CRATE.clone();
literals.push(quote!(#krate::format_args!(#lit);));
@ -400,7 +405,7 @@ fn concat_expand(
// FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
// to ensure the right parsing order, so skip the parentheses here. Ideally we'd
// implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
if let tt::TokenTree::Subtree(tt::Subtree { delimiter: Some(delim), token_trees }) = t {
if let tt::TokenTree::Subtree(tt::Subtree { delimiter: delim, token_trees }) = t {
if let [tt] = &**token_trees {
if delim.kind == tt::DelimiterKind::Parenthesis {
t = tt;
@ -459,9 +464,7 @@ fn concat_bytes_expand(
}
}
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
tt::TokenTree::Subtree(tree)
if tree.delimiter_kind() == Some(tt::DelimiterKind::Bracket) =>
{
tt::TokenTree::Subtree(tree) if tree.delimiter.kind == tt::DelimiterKind::Bracket => {
if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) {
err.get_or_insert(e);
break;
@ -473,7 +476,7 @@ fn concat_bytes_expand(
}
}
}
let ident = tt::Ident { text: bytes.join(", ").into(), id: tt::TokenId::unspecified() };
let ident = tt::Ident { text: bytes.join(", ").into(), span: tt::TokenId::unspecified() };
ExpandResult { value: ExpandedEager::new(quote!([#ident])), err }
}
@ -521,7 +524,7 @@ fn concat_idents_expand(
}
}
}
let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() };
let ident = tt::Ident { text: ident.into(), span: tt::TokenId::unspecified() };
ExpandResult { value: ExpandedEager::new(quote!(#ident)), err }
}
@ -572,7 +575,10 @@ fn include_expand(
Ok((subtree, file_id)) => {
ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) })
}
Err(e) => ExpandResult::only_err(e),
Err(e) => ExpandResult::with_err(
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
e,
),
}
}
@ -582,15 +588,18 @@ fn include_bytes_expand(
tt: &tt::Subtree,
) -> ExpandResult<ExpandedEager> {
if let Err(e) = parse_string(tt) {
return ExpandResult::only_err(e);
return ExpandResult::with_err(
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
e,
);
}
// FIXME: actually read the file here if the user asked for macro expansion
let res = tt::Subtree {
delimiter: None,
delimiter: tt::Delimiter::unspecified(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: r#"b"""#.into(),
id: tt::TokenId::unspecified(),
span: tt::TokenId::unspecified(),
}))],
};
ExpandResult::ok(ExpandedEager::new(res))
@ -603,7 +612,12 @@ fn include_str_expand(
) -> ExpandResult<ExpandedEager> {
let path = match parse_string(tt) {
Ok(it) => it,
Err(e) => return ExpandResult::only_err(e),
Err(e) => {
return ExpandResult::with_err(
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
e,
)
}
};
// FIXME: we're not able to read excluded files (which is most of them because
@ -635,7 +649,12 @@ fn env_expand(
) -> ExpandResult<ExpandedEager> {
let key = match parse_string(tt) {
Ok(it) => it,
Err(e) => return ExpandResult::only_err(e),
Err(e) => {
return ExpandResult::with_err(
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
e,
)
}
};
let mut err = None;
@ -666,7 +685,12 @@ fn option_env_expand(
) -> ExpandResult<ExpandedEager> {
let key = match parse_string(tt) {
Ok(it) => it,
Err(e) => return ExpandResult::only_err(e),
Err(e) => {
return ExpandResult::with_err(
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
e,
)
}
};
let expanded = match get_env_inner(db, arg_id, &key) {

View file

@ -14,7 +14,7 @@ use syntax::{
use crate::{
ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
hygiene::HygieneFrame, tt, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
};
@ -175,7 +175,7 @@ pub fn expand_speculative(
match attr.token_tree() {
Some(token_tree) => {
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
tree.delimiter = None;
tree.delimiter = tt::Delimiter::unspecified();
let shift = mbe::Shift::new(&tt);
shift.shift_all(&mut tree);
@ -210,7 +210,7 @@ pub fn expand_speculative(
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
let mut speculative_expansion = match loc.def.kind {
MacroDefKind::ProcMacro(expander, ..) => {
tt.delimiter = None;
tt.delimiter = tt::Delimiter::unspecified();
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
}
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
@ -316,9 +316,8 @@ fn macro_arg(
if loc.def.is_proc_macro() {
// proc macros expect their inputs without parentheses, MBEs expect it with them included
tt.delimiter = None;
tt.delimiter = tt::Delimiter::unspecified();
}
Some(Arc::new((tt, tmap, fixups.undo_info)))
}
@ -479,7 +478,10 @@ fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt::
let macro_arg = match db.macro_arg(id) {
Some(it) => it,
None => {
return ExpandResult::only_err(ExpandError::Other("No arguments for proc-macro".into()))
return ExpandResult::with_err(
tt::Subtree::empty(),
ExpandError::Other("No arguments for proc-macro".into()),
)
}
};

View file

@ -108,7 +108,7 @@ pub fn expand_eager_macro(
.value
.token_tree()
.map(|tt| mbe::syntax_node_to_token_tree(tt.syntax()).0)
.unwrap_or_default();
.unwrap_or_else(tt::Subtree::empty);
let ast_map = db.ast_id_map(macro_call.file_id);
let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
@ -165,9 +165,9 @@ pub fn expand_eager_macro(
}
}
fn to_subtree(node: &SyntaxNode) -> tt::Subtree {
fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree {
let mut subtree = mbe::syntax_node_to_token_tree(node).0;
subtree.delimiter = None;
subtree.delimiter = crate::tt::Delimiter::unspecified();
subtree
}

View file

@ -9,7 +9,7 @@ use syntax::{
ast::{self, AstNode, HasLoopBody},
match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
};
use tt::Subtree;
use tt::token_id::Subtree;
/// The result of calculating fixes for a syntax node -- a bunch of changes
/// (appending to and replacing nodes), the information that is needed to
@ -297,9 +297,11 @@ pub(crate) fn reverse_fixups(
tt.token_trees = tts
.into_iter()
.filter(|tt| match tt {
tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID),
tt::TokenTree::Leaf(leaf) => {
token_map.synthetic_token_id(*leaf.span()) != Some(EMPTY_ID)
}
tt::TokenTree::Subtree(st) => {
st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID))
token_map.synthetic_token_id(st.delimiter.open) != Some(EMPTY_ID)
}
})
.flat_map(|tt| match tt {
@ -308,9 +310,9 @@ pub(crate) fn reverse_fixups(
SmallVec::from_const([tt.into()])
}
tt::TokenTree::Leaf(leaf) => {
if let Some(id) = token_map.synthetic_token_id(leaf.id()) {
if let Some(id) = token_map.synthetic_token_id(*leaf.span()) {
let original = undo_info.original[id.0 as usize].clone();
if original.delimiter.is_none() {
if original.delimiter.kind == tt::DelimiterKind::Invisible {
original.token_trees.into()
} else {
SmallVec::from_const([original.into()])
@ -327,6 +329,8 @@ pub(crate) fn reverse_fixups(
mod tests {
use expect_test::{expect, Expect};
use crate::tt;
use super::reverse_fixups;
// The following three functions are only meant to check partial structural equivalence of
@ -341,7 +345,7 @@ mod tests {
}
fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool {
a.delimiter.map(|it| it.kind) == b.delimiter.map(|it| it.kind)
a.delimiter.kind == b.delimiter.kind
&& a.token_trees.len() == b.token_trees.len()
&& a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
}
@ -386,7 +390,7 @@ mod tests {
let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node());
assert!(
check_subtree_eq(&tt, &original_as_tt),
"different token tree: {tt:?}, {original_as_tt:?}"
"different token tree: {tt:?},\n{original_as_tt:?}"
);
}

View file

@ -128,7 +128,7 @@ struct HygieneInfo {
attr_input_or_mac_def_start: Option<InFile<TextSize>>,
macro_def: Arc<TokenExpander>,
macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
macro_arg: Arc<(crate::tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
macro_arg_shift: mbe::Shift,
exp_map: Arc<mbe::TokenMap>,
}

View file

@ -22,6 +22,8 @@ mod fixup;
pub use mbe::{Origin, ValueResult};
use ::tt::token_id as tt;
use std::{fmt, hash::Hash, iter, sync::Arc};
use base_db::{

View file

@ -191,7 +191,7 @@ impl AsName for ast::NameOrNameRef {
}
}
impl AsName for tt::Ident {
impl<Span> AsName for tt::Ident<Span> {
fn as_name(&self) -> Name {
Name::resolve(&self.text)
}

View file

@ -3,7 +3,7 @@
use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
use stdx::never;
use crate::{db::AstDatabase, ExpandError, ExpandResult};
use crate::{db::AstDatabase, tt, ExpandError, ExpandResult};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ProcMacroExpander {
@ -39,7 +39,10 @@ impl ProcMacroExpander {
Ok(proc_macros) => proc_macros,
Err(_) => {
never!("Non-dummy expander even though there are no proc macros");
return ExpandResult::only_err(ExpandError::Other("Internal error".into()));
return ExpandResult::with_err(
tt::Subtree::empty(),
ExpandError::Other("Internal error".into()),
);
}
};
let proc_macro = match proc_macros.get(id.0 as usize) {
@ -50,7 +53,10 @@ impl ProcMacroExpander {
proc_macros.len(),
id.0
);
return ExpandResult::only_err(ExpandError::Other("Internal error".into()));
return ExpandResult::with_err(
tt::Subtree::empty(),
ExpandError::Other("Internal error".into()),
);
}
};
@ -69,13 +75,17 @@ impl ProcMacroExpander {
}
}
ProcMacroExpansionError::System(text)
| ProcMacroExpansionError::Panic(text) => {
ExpandResult::only_err(ExpandError::Other(text.into()))
}
| ProcMacroExpansionError::Panic(text) => ExpandResult::with_err(
tt::Subtree::empty(),
ExpandError::Other(text.into()),
),
},
}
}
None => ExpandResult::only_err(ExpandError::UnresolvedProcMacro(self.krate)),
None => ExpandResult::with_err(
tt::Subtree::empty(),
ExpandError::UnresolvedProcMacro(self.krate),
),
}
}
}

View file

@ -9,17 +9,18 @@
#[macro_export]
macro_rules! __quote {
() => {
Vec::<tt::TokenTree>::new()
Vec::<crate::tt::TokenTree>::new()
};
( @SUBTREE $delim:ident $($tt:tt)* ) => {
{
let children = $crate::__quote!($($tt)*);
tt::Subtree {
delimiter: Some(tt::Delimiter {
kind: tt::DelimiterKind::$delim,
id: tt::TokenId::unspecified(),
}),
crate::tt::Subtree {
delimiter: crate::tt::Delimiter {
kind: crate::tt::DelimiterKind::$delim,
open: crate::tt::TokenId::unspecified(),
close: crate::tt::TokenId::unspecified(),
},
token_trees: $crate::quote::IntoTt::to_tokens(children),
}
}
@ -28,10 +29,10 @@ macro_rules! __quote {
( @PUNCT $first:literal ) => {
{
vec![
tt::Leaf::Punct(tt::Punct {
crate::tt::Leaf::Punct(crate::tt::Punct {
char: $first,
spacing: tt::Spacing::Alone,
id: tt::TokenId::unspecified(),
spacing: crate::tt::Spacing::Alone,
span: crate::tt::TokenId::unspecified(),
}).into()
]
}
@ -40,15 +41,15 @@ macro_rules! __quote {
( @PUNCT $first:literal, $sec:literal ) => {
{
vec![
tt::Leaf::Punct(tt::Punct {
crate::tt::Leaf::Punct(crate::tt::Punct {
char: $first,
spacing: tt::Spacing::Joint,
id: tt::TokenId::unspecified(),
spacing: crate::tt::Spacing::Joint,
span: crate::tt::TokenId::unspecified(),
}).into(),
tt::Leaf::Punct(tt::Punct {
crate::tt::Leaf::Punct(crate::tt::Punct {
char: $sec,
spacing: tt::Spacing::Alone,
id: tt::TokenId::unspecified(),
spacing: crate::tt::Spacing::Alone,
span: crate::tt::TokenId::unspecified(),
}).into()
]
}
@ -67,7 +68,7 @@ macro_rules! __quote {
( ## $first:ident $($tail:tt)* ) => {
{
let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<crate::tt::TokenTree>>();
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
tokens.append(&mut tail_tokens);
tokens
@ -86,9 +87,9 @@ macro_rules! __quote {
// Ident
( $tt:ident ) => {
vec![ {
tt::Leaf::Ident(tt::Ident {
crate::tt::Leaf::Ident(crate::tt::Ident {
text: stringify!($tt).into(),
id: tt::TokenId::unspecified(),
span: crate::tt::TokenId::unspecified(),
}).into()
}]
};
@ -127,42 +128,42 @@ macro_rules! quote {
}
pub(crate) trait IntoTt {
fn to_subtree(self) -> tt::Subtree;
fn to_tokens(self) -> Vec<tt::TokenTree>;
fn to_subtree(self) -> crate::tt::Subtree;
fn to_tokens(self) -> Vec<crate::tt::TokenTree>;
}
impl IntoTt for Vec<tt::TokenTree> {
fn to_subtree(self) -> tt::Subtree {
tt::Subtree { delimiter: None, token_trees: self }
impl IntoTt for Vec<crate::tt::TokenTree> {
fn to_subtree(self) -> crate::tt::Subtree {
crate::tt::Subtree { delimiter: crate::tt::Delimiter::unspecified(), token_trees: self }
}
fn to_tokens(self) -> Vec<tt::TokenTree> {
fn to_tokens(self) -> Vec<crate::tt::TokenTree> {
self
}
}
impl IntoTt for tt::Subtree {
fn to_subtree(self) -> tt::Subtree {
impl IntoTt for crate::tt::Subtree {
fn to_subtree(self) -> crate::tt::Subtree {
self
}
fn to_tokens(self) -> Vec<tt::TokenTree> {
vec![tt::TokenTree::Subtree(self)]
fn to_tokens(self) -> Vec<crate::tt::TokenTree> {
vec![crate::tt::TokenTree::Subtree(self)]
}
}
pub(crate) trait ToTokenTree {
fn to_token(self) -> tt::TokenTree;
fn to_token(self) -> crate::tt::TokenTree;
}
impl ToTokenTree for tt::TokenTree {
fn to_token(self) -> tt::TokenTree {
impl ToTokenTree for crate::tt::TokenTree {
fn to_token(self) -> crate::tt::TokenTree {
self
}
}
impl ToTokenTree for tt::Subtree {
fn to_token(self) -> tt::TokenTree {
impl ToTokenTree for crate::tt::Subtree {
fn to_token(self) -> crate::tt::TokenTree {
self.into()
}
}
@ -171,15 +172,15 @@ macro_rules! impl_to_to_tokentrees {
($($ty:ty => $this:ident $im:block);*) => {
$(
impl ToTokenTree for $ty {
fn to_token($this) -> tt::TokenTree {
let leaf: tt::Leaf = $im.into();
fn to_token($this) -> crate::tt::TokenTree {
let leaf: crate::tt::Leaf = $im.into();
leaf.into()
}
}
impl ToTokenTree for &$ty {
fn to_token($this) -> tt::TokenTree {
let leaf: tt::Leaf = $im.clone().into();
fn to_token($this) -> crate::tt::TokenTree {
let leaf: crate::tt::Leaf = $im.clone().into();
leaf.into()
}
}
@ -188,16 +189,16 @@ macro_rules! impl_to_to_tokentrees {
}
impl_to_to_tokentrees! {
u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
bool => self { tt::Ident{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
tt::Leaf => self { self };
tt::Literal => self { self };
tt::Ident => self { self };
tt::Punct => self { self };
&str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}};
String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}
u32 => self { crate::tt::Literal{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
usize => self { crate::tt::Literal{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
i32 => self { crate::tt::Literal{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
bool => self { crate::tt::Ident{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
crate::tt::Leaf => self { self };
crate::tt::Literal => self { self };
crate::tt::Ident => self { self };
crate::tt::Punct => self { self };
&str => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span: crate::tt::TokenId::unspecified()}};
String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span: crate::tt::TokenId::unspecified()}}
}
#[cfg(test)]
@ -223,8 +224,8 @@ mod tests {
assert_eq!(quote!(#s).to_string(), "\"hello\"");
}
fn mk_ident(name: &str) -> tt::Ident {
tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
fn mk_ident(name: &str) -> crate::tt::Ident {
crate::tt::Ident { text: name.into(), span: crate::tt::TokenId::unspecified() }
}
#[test]
@ -234,7 +235,7 @@ mod tests {
let quoted = quote!(#a);
assert_eq!(quoted.to_string(), "hello");
let t = format!("{quoted:?}");
assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295");
assert_eq!(t, "SUBTREE $$ 4294967295 4294967295\n IDENT hello 4294967295");
}
#[test]
@ -263,11 +264,12 @@ mod tests {
let fields = [mk_ident("name"), mk_ident("id")];
let fields = fields.iter().flat_map(|it| quote!(#it: self.#it.clone(), ).token_trees);
let list = tt::Subtree {
delimiter: Some(tt::Delimiter {
kind: tt::DelimiterKind::Brace,
id: tt::TokenId::unspecified(),
}),
let list = crate::tt::Subtree {
delimiter: crate::tt::Delimiter {
kind: crate::tt::DelimiterKind::Brace,
open: crate::tt::TokenId::unspecified(),
close: crate::tt::TokenId::unspecified(),
},
token_trees: fields.collect(),
};