mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Make tt generic over the span data
This commit is contained in:
parent
d805c74c51
commit
41a46a78f2
48 changed files with 806 additions and 569 deletions
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
}))
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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(¯o_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
|
||||
}
|
||||
|
||||
|
|
|
@ -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:?}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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::{
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue