mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Merge #6893
6893: Move to upstream `macro_rules!` model r=matklad a=jonas-schievink This changes `macro_rules!` from being treated as a macro invocation to being a first-class item. It also disallows using an additional ident argument for regular macros, so `m! ident(...);` now fails to parse. This matches upstream Rust, and makes the code somewhat simpler by removing repeated "is this a `macro_rules!` call" checks. It will also simplify allowing visibilities on macros, which is currently being proposed in https://github.com/rust-lang/rust/pull/78166. Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
bd4c352831
37 changed files with 338 additions and 276 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1827,9 +1827,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ungrammar"
|
name = "ungrammar"
|
||||||
version = "1.1.4"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df0cd89993af555540e2436fc6adb8479b0dbe386339a136397952e9c89e17a9"
|
checksum = "873186a460627379e7e28880a0d33b729c205634f6f021321f50b323235e62d7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
|
|
|
@ -25,3 +25,5 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
|
||||||
# chalk-solve = { path = "../chalk/chalk-solve" }
|
# chalk-solve = { path = "../chalk/chalk-solve" }
|
||||||
# chalk-ir = { path = "../chalk/chalk-ir" }
|
# chalk-ir = { path = "../chalk/chalk-ir" }
|
||||||
# chalk-recursive = { path = "../chalk/chalk-recursive" }
|
# chalk-recursive = { path = "../chalk/chalk-recursive" }
|
||||||
|
|
||||||
|
# ungrammar = { path = "../ungrammar" }
|
||||||
|
|
|
@ -144,7 +144,7 @@ mod tests {
|
||||||
use foo::<|>;
|
use foo::<|>;
|
||||||
//- /foo/lib.rs crate:foo
|
//- /foo/lib.rs crate:foo
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules frobnicate { () => () }
|
macro_rules! frobnicate { () => () }
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
use foo::frobnicate;
|
use foo::frobnicate;
|
||||||
|
@ -154,11 +154,11 @@ use foo::frobnicate;
|
||||||
check_edit(
|
check_edit(
|
||||||
"frobnicate!",
|
"frobnicate!",
|
||||||
r#"
|
r#"
|
||||||
macro_rules frobnicate { () => () }
|
macro_rules! frobnicate { () => () }
|
||||||
fn main() { frob<|>!(); }
|
fn main() { frob<|>!(); }
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
macro_rules frobnicate { () => () }
|
macro_rules! frobnicate { () => () }
|
||||||
fn main() { frobnicate!(); }
|
fn main() { frobnicate!(); }
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
|
@ -110,8 +110,8 @@ impl HasSource for TypeAlias {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl HasSource for MacroDef {
|
impl HasSource for MacroDef {
|
||||||
type Ast = ast::MacroCall;
|
type Ast = ast::MacroRules;
|
||||||
fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroCall> {
|
fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroRules> {
|
||||||
InFile {
|
InFile {
|
||||||
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
|
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
|
||||||
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
|
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
|
||||||
|
|
|
@ -723,7 +723,7 @@ to_def_impls![
|
||||||
(crate::EnumVariant, ast::Variant, enum_variant_to_def),
|
(crate::EnumVariant, ast::Variant, enum_variant_to_def),
|
||||||
(crate::TypeParam, ast::TypeParam, type_param_to_def),
|
(crate::TypeParam, ast::TypeParam, type_param_to_def),
|
||||||
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
|
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
|
||||||
(crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros
|
(crate::MacroDef, ast::MacroRules, macro_rules_to_def),
|
||||||
(crate::Local, ast::IdentPat, bind_pat_to_def),
|
(crate::Local, ast::IdentPat, bind_pat_to_def),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,10 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: use DynMap as well?
|
// FIXME: use DynMap as well?
|
||||||
pub(super) fn macro_call_to_def(&mut self, src: InFile<ast::MacroCall>) -> Option<MacroDefId> {
|
pub(super) fn macro_rules_to_def(
|
||||||
|
&mut self,
|
||||||
|
src: InFile<ast::MacroRules>,
|
||||||
|
) -> Option<MacroDefId> {
|
||||||
let kind = MacroDefKind::Declarative;
|
let kind = MacroDefKind::Declarative;
|
||||||
let file_id = src.file_id.original_file(self.db.upcast());
|
let file_id = src.file_id.original_file(self.db.upcast());
|
||||||
let krate = self.file_to_def(file_id)?.krate;
|
let krate = self.file_to_def(file_id)?.krate;
|
||||||
|
|
|
@ -566,66 +566,52 @@ impl ExprCollector<'_> {
|
||||||
syntax_ptr: AstPtr<ast::Expr>,
|
syntax_ptr: AstPtr<ast::Expr>,
|
||||||
mut collector: F,
|
mut collector: F,
|
||||||
) {
|
) {
|
||||||
if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) {
|
// File containing the macro call. Expansion errors will be attached here.
|
||||||
let mac = MacroDefId {
|
let outer_file = self.expander.current_file_id;
|
||||||
krate: Some(self.expander.module.krate),
|
|
||||||
ast_id: Some(self.expander.ast_id(&e)),
|
|
||||||
kind: MacroDefKind::Declarative,
|
|
||||||
local_inner: false,
|
|
||||||
};
|
|
||||||
self.body.item_scope.define_legacy_macro(name, mac);
|
|
||||||
|
|
||||||
// FIXME: do we still need to allocate this as missing ?
|
let macro_call = self.expander.to_source(AstPtr::new(&e));
|
||||||
collector(self, None);
|
let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
|
||||||
} else {
|
|
||||||
// File containing the macro call. Expansion errors will be attached here.
|
|
||||||
let outer_file = self.expander.current_file_id;
|
|
||||||
|
|
||||||
let macro_call = self.expander.to_source(AstPtr::new(&e));
|
match &res.err {
|
||||||
let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
|
Some(ExpandError::UnresolvedProcMacro) => {
|
||||||
|
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
|
||||||
match &res.err {
|
UnresolvedProcMacro {
|
||||||
Some(ExpandError::UnresolvedProcMacro) => {
|
|
||||||
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
|
|
||||||
UnresolvedProcMacro {
|
|
||||||
file: outer_file,
|
|
||||||
node: syntax_ptr.into(),
|
|
||||||
precise_location: None,
|
|
||||||
macro_name: None,
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Some(err) => {
|
|
||||||
self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
|
|
||||||
file: outer_file,
|
file: outer_file,
|
||||||
node: syntax_ptr.into(),
|
node: syntax_ptr.into(),
|
||||||
message: err.to_string(),
|
precise_location: None,
|
||||||
}));
|
macro_name: None,
|
||||||
}
|
},
|
||||||
None => {}
|
));
|
||||||
}
|
}
|
||||||
|
Some(err) => {
|
||||||
match res.value {
|
self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
|
||||||
Some((mark, expansion)) => {
|
file: outer_file,
|
||||||
// FIXME: Statements are too complicated to recover from error for now.
|
node: syntax_ptr.into(),
|
||||||
// It is because we don't have any hygenine for local variable expansion right now.
|
message: err.to_string(),
|
||||||
if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
|
}));
|
||||||
self.expander.exit(self.db, mark);
|
|
||||||
collector(self, None);
|
|
||||||
} else {
|
|
||||||
self.source_map
|
|
||||||
.expansions
|
|
||||||
.insert(macro_call, self.expander.current_file_id);
|
|
||||||
|
|
||||||
let item_tree = self.db.item_tree(self.expander.current_file_id);
|
|
||||||
self.item_trees.insert(self.expander.current_file_id, item_tree);
|
|
||||||
|
|
||||||
collector(self, Some(expansion));
|
|
||||||
self.expander.exit(self.db, mark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => collector(self, None),
|
|
||||||
}
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match res.value {
|
||||||
|
Some((mark, expansion)) => {
|
||||||
|
// FIXME: Statements are too complicated to recover from error for now.
|
||||||
|
// It is because we don't have any hygenine for local variable expansion right now.
|
||||||
|
if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
|
||||||
|
self.expander.exit(self.db, mark);
|
||||||
|
collector(self, None);
|
||||||
|
} else {
|
||||||
|
self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
|
||||||
|
|
||||||
|
let item_tree = self.db.item_tree(self.expander.current_file_id);
|
||||||
|
self.item_trees.insert(self.expander.current_file_id, item_tree);
|
||||||
|
|
||||||
|
let id = collector(self, Some(expansion));
|
||||||
|
self.expander.exit(self.db, mark);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => collector(self, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,26 +771,44 @@ impl ExprCollector<'_> {
|
||||||
| ast::Item::ExternCrate(_)
|
| ast::Item::ExternCrate(_)
|
||||||
| ast::Item::Module(_)
|
| ast::Item::Module(_)
|
||||||
| ast::Item::MacroCall(_) => return None,
|
| ast::Item::MacroCall(_) => return None,
|
||||||
|
ast::Item::MacroRules(def) => {
|
||||||
|
return Some(Either::Right(def));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((def, name))
|
Some(Either::Left((def, name)))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for (def, name) in items {
|
for either in items {
|
||||||
self.body.item_scope.define_def(def);
|
match either {
|
||||||
if let Some(name) = name {
|
Either::Left((def, name)) => {
|
||||||
let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
|
self.body.item_scope.define_def(def);
|
||||||
let has_constructor = match def {
|
if let Some(name) = name {
|
||||||
ModuleDefId::AdtId(AdtId::StructId(s)) => {
|
let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
|
||||||
self.db.struct_data(s).variant_data.kind() != StructKind::Record
|
let has_constructor = match def {
|
||||||
|
ModuleDefId::AdtId(AdtId::StructId(s)) => {
|
||||||
|
self.db.struct_data(s).variant_data.kind() != StructKind::Record
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
self.body.item_scope.push_res(
|
||||||
|
name.as_name(),
|
||||||
|
crate::per_ns::PerNs::from_def(def, vis, has_constructor),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => true,
|
}
|
||||||
};
|
Either::Right(e) => {
|
||||||
self.body.item_scope.push_res(
|
let mac = MacroDefId {
|
||||||
name.as_name(),
|
krate: Some(self.expander.module.krate),
|
||||||
crate::per_ns::PerNs::from_def(def, vis, has_constructor),
|
ast_id: Some(self.expander.ast_id(&e)),
|
||||||
);
|
kind: MacroDefKind::Declarative,
|
||||||
|
local_inner: false,
|
||||||
|
};
|
||||||
|
if let Some(name) = e.name() {
|
||||||
|
self.body.item_scope.define_legacy_macro(name.as_name(), mac);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,7 @@ impl ItemTree {
|
||||||
type_aliases,
|
type_aliases,
|
||||||
mods,
|
mods,
|
||||||
macro_calls,
|
macro_calls,
|
||||||
|
macro_rules,
|
||||||
exprs,
|
exprs,
|
||||||
vis,
|
vis,
|
||||||
generics,
|
generics,
|
||||||
|
@ -162,6 +163,7 @@ impl ItemTree {
|
||||||
type_aliases.shrink_to_fit();
|
type_aliases.shrink_to_fit();
|
||||||
mods.shrink_to_fit();
|
mods.shrink_to_fit();
|
||||||
macro_calls.shrink_to_fit();
|
macro_calls.shrink_to_fit();
|
||||||
|
macro_rules.shrink_to_fit();
|
||||||
exprs.shrink_to_fit();
|
exprs.shrink_to_fit();
|
||||||
|
|
||||||
vis.arena.shrink_to_fit();
|
vis.arena.shrink_to_fit();
|
||||||
|
@ -280,6 +282,7 @@ struct ItemTreeData {
|
||||||
type_aliases: Arena<TypeAlias>,
|
type_aliases: Arena<TypeAlias>,
|
||||||
mods: Arena<Mod>,
|
mods: Arena<Mod>,
|
||||||
macro_calls: Arena<MacroCall>,
|
macro_calls: Arena<MacroCall>,
|
||||||
|
macro_rules: Arena<MacroRules>,
|
||||||
exprs: Arena<Expr>,
|
exprs: Arena<Expr>,
|
||||||
|
|
||||||
vis: ItemVisibilities,
|
vis: ItemVisibilities,
|
||||||
|
@ -427,6 +430,7 @@ mod_items! {
|
||||||
TypeAlias in type_aliases -> ast::TypeAlias,
|
TypeAlias in type_aliases -> ast::TypeAlias,
|
||||||
Mod in mods -> ast::Module,
|
Mod in mods -> ast::Module,
|
||||||
MacroCall in macro_calls -> ast::MacroCall,
|
MacroCall in macro_calls -> ast::MacroCall,
|
||||||
|
MacroRules in macro_rules -> ast::MacroRules,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_index {
|
macro_rules! impl_index {
|
||||||
|
@ -629,17 +633,22 @@ pub enum ModKind {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MacroCall {
|
pub struct MacroCall {
|
||||||
/// For `macro_rules!` declarations, this is the name of the declared macro.
|
|
||||||
pub name: Option<Name>,
|
|
||||||
/// Path to the called macro.
|
/// Path to the called macro.
|
||||||
pub path: ModPath,
|
pub path: ModPath,
|
||||||
|
pub ast_id: FileAstId<ast::MacroCall>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct MacroRules {
|
||||||
|
/// For `macro_rules!` declarations, this is the name of the declared macro.
|
||||||
|
pub name: Name,
|
||||||
/// Has `#[macro_export]`.
|
/// Has `#[macro_export]`.
|
||||||
pub is_export: bool,
|
pub is_export: bool,
|
||||||
/// Has `#[macro_export(local_inner_macros)]`.
|
/// Has `#[macro_export(local_inner_macros)]`.
|
||||||
pub is_local_inner: bool,
|
pub is_local_inner: bool,
|
||||||
/// Has `#[rustc_builtin_macro]`.
|
/// Has `#[rustc_builtin_macro]`.
|
||||||
pub is_builtin: bool,
|
pub is_builtin: bool,
|
||||||
pub ast_id: FileAstId<ast::MacroCall>,
|
pub ast_id: FileAstId<ast::MacroRules>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
|
// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
|
||||||
|
@ -670,7 +679,8 @@ impl ModItem {
|
||||||
| ModItem::Static(_)
|
| ModItem::Static(_)
|
||||||
| ModItem::Trait(_)
|
| ModItem::Trait(_)
|
||||||
| ModItem::Impl(_)
|
| ModItem::Impl(_)
|
||||||
| ModItem::Mod(_) => None,
|
| ModItem::Mod(_)
|
||||||
|
| ModItem::MacroRules(_) => None,
|
||||||
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
|
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
|
||||||
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
|
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
|
||||||
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
|
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
|
||||||
|
@ -697,6 +707,7 @@ impl ModItem {
|
||||||
ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
|
ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
|
||||||
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
|
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
|
||||||
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
|
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
|
||||||
|
ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,8 +84,7 @@ impl Ctx {
|
||||||
| ast::Item::Fn(_)
|
| ast::Item::Fn(_)
|
||||||
| ast::Item::TypeAlias(_)
|
| ast::Item::TypeAlias(_)
|
||||||
| ast::Item::Const(_)
|
| ast::Item::Const(_)
|
||||||
| ast::Item::Static(_)
|
| ast::Item::Static(_) => {
|
||||||
| ast::Item::MacroCall(_) => {
|
|
||||||
// Skip this if we're already collecting inner items. We'll descend into all nodes
|
// Skip this if we're already collecting inner items. We'll descend into all nodes
|
||||||
// already.
|
// already.
|
||||||
if !inner {
|
if !inner {
|
||||||
|
@ -98,7 +97,11 @@ impl Ctx {
|
||||||
ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
|
ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
|
||||||
|
|
||||||
// These don't have inner items.
|
// These don't have inner items.
|
||||||
ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
|
ast::Item::Module(_)
|
||||||
|
| ast::Item::ExternCrate(_)
|
||||||
|
| ast::Item::Use(_)
|
||||||
|
| ast::Item::MacroCall(_)
|
||||||
|
| ast::Item::MacroRules(_) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let attrs = Attrs::new(item, &self.hygiene);
|
let attrs = Attrs::new(item, &self.hygiene);
|
||||||
|
@ -118,6 +121,7 @@ impl Ctx {
|
||||||
)),
|
)),
|
||||||
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
|
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
|
||||||
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
|
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
|
||||||
|
ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
|
||||||
ast::Item::ExternBlock(ast) => {
|
ast::Item::ExternBlock(ast) => {
|
||||||
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
|
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
|
||||||
}
|
}
|
||||||
|
@ -525,9 +529,15 @@ impl Ctx {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
|
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
|
||||||
let name = m.name().map(|it| it.as_name());
|
|
||||||
let attrs = Attrs::new(m, &self.hygiene);
|
|
||||||
let path = ModPath::from_src(m.path()?, &self.hygiene)?;
|
let path = ModPath::from_src(m.path()?, &self.hygiene)?;
|
||||||
|
let ast_id = self.source_ast_id_map.ast_id(m);
|
||||||
|
let res = MacroCall { path, ast_id };
|
||||||
|
Some(id(self.data().macro_calls.alloc(res)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
|
||||||
|
let name = m.name().map(|it| it.as_name())?;
|
||||||
|
let attrs = Attrs::new(m, &self.hygiene);
|
||||||
|
|
||||||
let ast_id = self.source_ast_id_map.ast_id(m);
|
let ast_id = self.source_ast_id_map.ast_id(m);
|
||||||
|
|
||||||
|
@ -547,8 +557,8 @@ impl Ctx {
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
|
let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
|
||||||
let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
|
let res = MacroRules { name, is_export, is_builtin, is_local_inner, ast_id };
|
||||||
Some(id(self.data().macro_calls.alloc(res)))
|
Some(id(self.data().macro_rules.alloc(res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
|
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use hir_expand::{
|
||||||
ast_id_map::FileAstId,
|
ast_id_map::FileAstId,
|
||||||
builtin_derive::find_builtin_derive,
|
builtin_derive::find_builtin_derive,
|
||||||
builtin_macro::find_builtin_macro,
|
builtin_macro::find_builtin_macro,
|
||||||
name::{name, AsName, Name},
|
name::{AsName, Name},
|
||||||
proc_macro::ProcMacroExpander,
|
proc_macro::ProcMacroExpander,
|
||||||
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
|
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,9 @@ use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
item_scope::{ImportType, PerNsGlobImports},
|
item_scope::{ImportType, PerNsGlobImports},
|
||||||
item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind},
|
item_tree::{
|
||||||
|
self, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, StructDefKind,
|
||||||
|
},
|
||||||
nameres::{
|
nameres::{
|
||||||
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
|
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
|
||||||
BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
|
BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
|
||||||
|
@ -972,7 +974,8 @@ impl ModCollector<'_, '_> {
|
||||||
status: PartialResolvedImport::Unresolved,
|
status: PartialResolvedImport::Unresolved,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
|
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
|
||||||
|
ModItem::MacroRules(mac) => self.collect_macro_rules(&self.item_tree[mac]),
|
||||||
ModItem::Impl(imp) => {
|
ModItem::Impl(imp) => {
|
||||||
let module = ModuleId {
|
let module = ModuleId {
|
||||||
krate: self.def_collector.def_map.krate,
|
krate: self.def_collector.def_map.krate,
|
||||||
|
@ -1276,45 +1279,37 @@ impl ModCollector<'_, '_> {
|
||||||
self.def_collector.resolve_proc_macro(¯o_name);
|
self.def_collector.resolve_proc_macro(¯o_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_macro(&mut self, mac: &MacroCall) {
|
fn collect_macro_rules(&mut self, mac: &MacroRules) {
|
||||||
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
let ast_id = InFile::new(self.file_id, mac.ast_id);
|
||||||
|
|
||||||
// Case 0: builtin macros
|
// Case 1: builtin macros
|
||||||
if mac.is_builtin {
|
if mac.is_builtin {
|
||||||
if let Some(name) = &mac.name {
|
let krate = self.def_collector.def_map.krate;
|
||||||
let krate = self.def_collector.def_map.krate;
|
if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) {
|
||||||
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
|
|
||||||
self.def_collector.define_macro(
|
|
||||||
self.module_id,
|
|
||||||
name.clone(),
|
|
||||||
macro_id,
|
|
||||||
mac.is_export,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 1: macro rules, define a macro in crate-global mutable scope
|
|
||||||
if is_macro_rules(&mac.path) {
|
|
||||||
if let Some(name) = &mac.name {
|
|
||||||
let macro_id = MacroDefId {
|
|
||||||
ast_id: Some(ast_id.ast_id),
|
|
||||||
krate: Some(self.def_collector.def_map.krate),
|
|
||||||
kind: MacroDefKind::Declarative,
|
|
||||||
local_inner: mac.is_local_inner,
|
|
||||||
};
|
|
||||||
self.def_collector.define_macro(
|
self.def_collector.define_macro(
|
||||||
self.module_id,
|
self.module_id,
|
||||||
name.clone(),
|
mac.name.clone(),
|
||||||
macro_id,
|
macro_id,
|
||||||
mac.is_export,
|
mac.is_export,
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2: try to resolve in legacy scope and expand macro_rules
|
// Case 2: normal `macro_rules!` macro
|
||||||
|
let macro_id = MacroDefId {
|
||||||
|
ast_id: Some(ast_id),
|
||||||
|
krate: Some(self.def_collector.def_map.krate),
|
||||||
|
kind: MacroDefKind::Declarative,
|
||||||
|
local_inner: mac.is_local_inner,
|
||||||
|
};
|
||||||
|
self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, mac.is_export);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_macro_call(&mut self, mac: &MacroCall) {
|
||||||
|
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
||||||
|
|
||||||
|
// Case 1: try to resolve in legacy scope and expand macro_rules
|
||||||
if let Some(macro_call_id) =
|
if let Some(macro_call_id) =
|
||||||
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
|
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
|
||||||
path.as_ident().and_then(|name| {
|
path.as_ident().and_then(|name| {
|
||||||
|
@ -1332,7 +1327,7 @@ impl ModCollector<'_, '_> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 3: resolve in module scope, expand during name resolution.
|
// Case 2: resolve in module scope, expand during name resolution.
|
||||||
// We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
|
// We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
|
||||||
if ast_id.path.is_ident() {
|
if ast_id.path.is_ident() {
|
||||||
ast_id.path.kind = PathKind::Super(0);
|
ast_id.path.kind = PathKind::Super(0);
|
||||||
|
@ -1370,10 +1365,6 @@ impl ModCollector<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_macro_rules(path: &ModPath) -> bool {
|
|
||||||
path.as_ident() == Some(&name![macro_rules])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{db::DefDatabase, test_db::TestDB};
|
use crate::{db::DefDatabase, test_db::TestDB};
|
||||||
|
|
|
@ -122,11 +122,9 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
|
||||||
// https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
|
// https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
|
||||||
// We follow what it did anyway :)
|
// We follow what it did anyway :)
|
||||||
if segments.len() == 1 && kind == PathKind::Plain {
|
if segments.len() == 1 && kind == PathKind::Plain {
|
||||||
if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
|
if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
|
||||||
if macro_call.is_bang() {
|
if let Some(crate_id) = hygiene.local_inner_macros() {
|
||||||
if let Some(crate_id) = hygiene.local_inner_macros() {
|
kind = PathKind::DollarCrate(crate_id);
|
||||||
kind = PathKind::DollarCrate(crate_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ macro_rules! register_builtin {
|
||||||
pub fn find_builtin_macro(
|
pub fn find_builtin_macro(
|
||||||
ident: &name::Name,
|
ident: &name::Name,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
ast_id: AstId<ast::MacroCall>,
|
ast_id: AstId<ast::MacroRules>,
|
||||||
) -> Option<MacroDefId> {
|
) -> Option<MacroDefId> {
|
||||||
let kind = find_by_name(ident)?;
|
let kind = find_by_name(ident)?;
|
||||||
|
|
||||||
|
@ -515,12 +515,16 @@ mod tests {
|
||||||
fn expand_builtin_macro(ra_fixture: &str) -> String {
|
fn expand_builtin_macro(ra_fixture: &str) -> String {
|
||||||
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
|
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
|
||||||
let parsed = db.parse(file_id);
|
let parsed = db.parse(file_id);
|
||||||
|
let macro_rules: Vec<_> =
|
||||||
|
parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect();
|
||||||
let macro_calls: Vec<_> =
|
let macro_calls: Vec<_> =
|
||||||
parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect();
|
parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect();
|
||||||
|
|
||||||
let ast_id_map = db.ast_id_map(file_id.into());
|
let ast_id_map = db.ast_id_map(file_id.into());
|
||||||
|
|
||||||
let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap();
|
assert_eq!(macro_rules.len(), 1, "test must contain exactly 1 `macro_rules!`");
|
||||||
|
assert_eq!(macro_calls.len(), 1, "test must contain exactly 1 macro call");
|
||||||
|
let expander = find_by_name(¯o_rules[0].name().unwrap().as_name()).unwrap();
|
||||||
|
|
||||||
let krate = CrateId(0);
|
let krate = CrateId(0);
|
||||||
let file_id = match expander {
|
let file_id = match expander {
|
||||||
|
@ -528,7 +532,7 @@ mod tests {
|
||||||
// the first one should be a macro_rules
|
// the first one should be a macro_rules
|
||||||
let def = MacroDefId {
|
let def = MacroDefId {
|
||||||
krate: Some(CrateId(0)),
|
krate: Some(CrateId(0)),
|
||||||
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))),
|
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules[0]))),
|
||||||
kind: MacroDefKind::BuiltIn(expander),
|
kind: MacroDefKind::BuiltIn(expander),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
};
|
};
|
||||||
|
@ -538,7 +542,7 @@ mod tests {
|
||||||
krate,
|
krate,
|
||||||
kind: MacroCallKind::FnLike(AstId::new(
|
kind: MacroCallKind::FnLike(AstId::new(
|
||||||
file_id.into(),
|
file_id.into(),
|
||||||
ast_id_map.ast_id(¯o_calls[1]),
|
ast_id_map.ast_id(¯o_calls[0]),
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -549,12 +553,12 @@ mod tests {
|
||||||
// the first one should be a macro_rules
|
// the first one should be a macro_rules
|
||||||
let def = MacroDefId {
|
let def = MacroDefId {
|
||||||
krate: Some(krate),
|
krate: Some(krate),
|
||||||
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))),
|
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules[0]))),
|
||||||
kind: MacroDefKind::BuiltInEager(expander),
|
kind: MacroDefKind::BuiltInEager(expander),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = macro_calls[1].token_tree().unwrap();
|
let args = macro_calls[0].token_tree().unwrap();
|
||||||
let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0;
|
let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0;
|
||||||
|
|
||||||
let arg_id = db.intern_eager_expansion({
|
let arg_id = db.intern_eager_expansion({
|
||||||
|
|
|
@ -228,7 +228,7 @@ pub struct MacroDefId {
|
||||||
// (which will probably require touching this code), we can instead use
|
// (which will probably require touching this code), we can instead use
|
||||||
// that (and also remove the hacks for resolving built-in derives).
|
// that (and also remove the hacks for resolving built-in derives).
|
||||||
pub krate: Option<CrateId>,
|
pub krate: Option<CrateId>,
|
||||||
pub ast_id: Option<AstId<ast::MacroCall>>,
|
pub ast_id: Option<AstId<ast::MacroRules>>,
|
||||||
pub kind: MacroDefKind,
|
pub kind: MacroDefKind,
|
||||||
|
|
||||||
pub local_inner: bool,
|
pub local_inner: bool,
|
||||||
|
|
|
@ -413,7 +413,6 @@ fn infer_local_macro() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
!0..6 '1usize': usize
|
!0..6 '1usize': usize
|
||||||
10..89 '{ ...!(); }': ()
|
10..89 '{ ...!(); }': ()
|
||||||
16..65 'macro_... }': {unknown}
|
|
||||||
74..76 '_a': usize
|
74..76 '_a': usize
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -150,13 +150,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
|
||||||
};
|
};
|
||||||
Some(node)
|
Some(node)
|
||||||
},
|
},
|
||||||
ast::MacroCall(it) => {
|
ast::MacroRules(it) => decl(it),
|
||||||
match it.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) {
|
|
||||||
Some(path_segment) if path_segment.text() == "macro_rules"
|
|
||||||
=> decl(it),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,7 +374,7 @@ fn very_obsolete() {}
|
||||||
label: "mc",
|
label: "mc",
|
||||||
navigation_range: 284..286,
|
navigation_range: 284..286,
|
||||||
node_range: 271..303,
|
node_range: 271..303,
|
||||||
kind: MACRO_CALL,
|
kind: MACRO_RULES,
|
||||||
detail: None,
|
detail: None,
|
||||||
deprecated: false,
|
deprecated: false,
|
||||||
},
|
},
|
||||||
|
@ -389,7 +383,7 @@ fn very_obsolete() {}
|
||||||
label: "mcexp",
|
label: "mcexp",
|
||||||
navigation_range: 334..339,
|
navigation_range: 334..339,
|
||||||
node_range: 305..356,
|
node_range: 305..356,
|
||||||
kind: MACRO_CALL,
|
kind: MACRO_RULES,
|
||||||
detail: None,
|
detail: None,
|
||||||
deprecated: false,
|
deprecated: false,
|
||||||
},
|
},
|
||||||
|
@ -398,7 +392,7 @@ fn very_obsolete() {}
|
||||||
label: "mcexp",
|
label: "mcexp",
|
||||||
navigation_range: 387..392,
|
navigation_range: 387..392,
|
||||||
node_range: 358..409,
|
node_range: 358..409,
|
||||||
kind: MACRO_CALL,
|
kind: MACRO_RULES,
|
||||||
detail: None,
|
detail: None,
|
||||||
deprecated: false,
|
deprecated: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -770,7 +770,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
m1 MACRO_CALL FileId(0) 0..46 29..31 Other
|
m1 MACRO_RULES FileId(0) 0..46 29..31 Other
|
||||||
|
|
||||||
FileId(0) 63..65 StructLiteral
|
FileId(0) 63..65 StructLiteral
|
||||||
FileId(0) 73..75 StructLiteral
|
FileId(0) 73..75 StructLiteral
|
||||||
|
|
|
@ -74,6 +74,7 @@ pub(crate) fn highlight(
|
||||||
let mut stack = HighlightedRangeStack::new();
|
let mut stack = HighlightedRangeStack::new();
|
||||||
|
|
||||||
let mut current_macro_call: Option<ast::MacroCall> = None;
|
let mut current_macro_call: Option<ast::MacroCall> = None;
|
||||||
|
let mut current_macro_rules: Option<ast::MacroRules> = None;
|
||||||
let mut format_string_highlighter = FormatStringHighlighter::default();
|
let mut format_string_highlighter = FormatStringHighlighter::default();
|
||||||
let mut macro_rules_highlighter = MacroRulesHighlighter::default();
|
let mut macro_rules_highlighter = MacroRulesHighlighter::default();
|
||||||
let mut inside_attribute = false;
|
let mut inside_attribute = false;
|
||||||
|
@ -106,28 +107,26 @@ pub(crate) fn highlight(
|
||||||
binding_hash: None,
|
binding_hash: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(name) = mc.is_macro_rules() {
|
|
||||||
macro_rules_highlighter.init();
|
|
||||||
if let Some((highlight, binding_hash)) = highlight_element(
|
|
||||||
&sema,
|
|
||||||
&mut bindings_shadow_count,
|
|
||||||
syntactic_name_ref_highlighting,
|
|
||||||
name.syntax().clone().into(),
|
|
||||||
) {
|
|
||||||
stack.add(HighlightedRange {
|
|
||||||
range: name.syntax().text_range(),
|
|
||||||
highlight,
|
|
||||||
binding_hash,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current_macro_call = Some(mc.clone());
|
current_macro_call = Some(mc.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
WalkEvent::Leave(Some(mc)) => {
|
WalkEvent::Leave(Some(mc)) => {
|
||||||
assert!(current_macro_call == Some(mc));
|
assert_eq!(current_macro_call, Some(mc));
|
||||||
current_macro_call = None;
|
current_macro_call = None;
|
||||||
format_string_highlighter = FormatStringHighlighter::default();
|
format_string_highlighter = FormatStringHighlighter::default();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) {
|
||||||
|
WalkEvent::Enter(Some(mac)) => {
|
||||||
|
macro_rules_highlighter.init();
|
||||||
|
current_macro_rules = Some(mac);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
WalkEvent::Leave(Some(mac)) => {
|
||||||
|
assert_eq!(current_macro_rules, Some(mac));
|
||||||
|
current_macro_rules = None;
|
||||||
macro_rules_highlighter = MacroRulesHighlighter::default();
|
macro_rules_highlighter = MacroRulesHighlighter::default();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -163,6 +162,12 @@ pub(crate) fn highlight(
|
||||||
|
|
||||||
let range = element.text_range();
|
let range = element.text_range();
|
||||||
|
|
||||||
|
if current_macro_rules.is_some() {
|
||||||
|
if let Some(tok) = element.as_token() {
|
||||||
|
macro_rules_highlighter.advance(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT {
|
let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT {
|
||||||
// Inside a macro -- expand it first
|
// Inside a macro -- expand it first
|
||||||
let token = match element.clone().into_token() {
|
let token = match element.clone().into_token() {
|
||||||
|
@ -173,9 +178,6 @@ pub(crate) fn highlight(
|
||||||
let parent = token.parent();
|
let parent = token.parent();
|
||||||
|
|
||||||
format_string_highlighter.check_for_format_string(&parent);
|
format_string_highlighter.check_for_format_string(&parent);
|
||||||
if let Some(tok) = element.as_token() {
|
|
||||||
macro_rules_highlighter.advance(tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only care Name and Name_ref
|
// We only care Name and Name_ref
|
||||||
match (token.kind(), parent.kind()) {
|
match (token.kind(), parent.kind()) {
|
||||||
|
@ -386,10 +388,14 @@ impl HighlightedRangeStack {
|
||||||
let mut res = self.stack.pop().unwrap();
|
let mut res = self.stack.pop().unwrap();
|
||||||
res.sort_by_key(|range| range.range.start());
|
res.sort_by_key(|range| range.range.start());
|
||||||
// Check that ranges are sorted and disjoint
|
// Check that ranges are sorted and disjoint
|
||||||
assert!(res
|
for (left, right) in res.iter().zip(res.iter().skip(1)) {
|
||||||
.iter()
|
assert!(
|
||||||
.zip(res.iter().skip(1))
|
left.range.end() <= right.range.start(),
|
||||||
.all(|(left, right)| left.range.end() <= right.range.start()));
|
"left: {:#?}, right: {:#?}",
|
||||||
|
left,
|
||||||
|
right
|
||||||
|
);
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="comment documentation">/// ```</span>
|
<span class="comment documentation">/// ```</span>
|
||||||
<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected">
|
<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected">
|
||||||
</span><span class="comment documentation">/// ```</span>
|
</span><span class="comment documentation">/// ```</span>
|
||||||
<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
|
<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">$</span>expr
|
<span class="punctuation">$</span>expr
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
|
@ -35,13 +35,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
|
|
||||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||||
</style>
|
</style>
|
||||||
<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
|
<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">{</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">{</span>
|
||||||
<span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
<span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
||||||
<span class="punctuation">}</span><span class="punctuation">)</span>
|
<span class="punctuation">}</span><span class="punctuation">)</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
#[rustc_builtin_macro]
|
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
|
||||||
<span class="macro">macro_rules!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span>
|
<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
|
@ -125,7 +125,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
||||||
<span class="macro">macro_rules!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span>
|
<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
||||||
|
@ -135,13 +135,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
||||||
<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
|
<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">$</span>expr
|
<span class="punctuation">$</span>expr
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
||||||
<span class="macro">macro_rules!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span>
|
<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span>
|
||||||
<span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span>
|
<span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">></span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ impl NameClass {
|
||||||
let def: hir::TypeAlias = sema.to_def(&it)?;
|
let def: hir::TypeAlias = sema.to_def(&it)?;
|
||||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||||
},
|
},
|
||||||
ast::MacroCall(it) => {
|
ast::MacroRules(it) => {
|
||||||
let def = sema.to_def(&it)?;
|
let def = sema.to_def(&it)?;
|
||||||
Some(NameClass::Definition(Definition::Macro(def)))
|
Some(NameClass::Definition(Definition::Macro(def)))
|
||||||
},
|
},
|
||||||
|
|
|
@ -404,13 +404,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
|
||||||
ast::TypeAlias(it) => decl(it),
|
ast::TypeAlias(it) => decl(it),
|
||||||
ast::Const(it) => decl(it),
|
ast::Const(it) => decl(it),
|
||||||
ast::Static(it) => decl(it),
|
ast::Static(it) => decl(it),
|
||||||
ast::MacroCall(it) => {
|
ast::MacroRules(it) => decl(it),
|
||||||
if it.is_macro_rules().is_some() {
|
|
||||||
decl(it)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ mod tests {
|
||||||
fn create_rules(macro_definition: &str) -> crate::MacroRules {
|
fn create_rules(macro_definition: &str) -> crate::MacroRules {
|
||||||
let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
|
let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
|
||||||
let macro_definition =
|
let macro_definition =
|
||||||
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
|
||||||
|
|
||||||
let (definition_tt, _) =
|
let (definition_tt, _) =
|
||||||
ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap();
|
ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap();
|
||||||
|
|
|
@ -48,7 +48,7 @@ mod rule_parsing {
|
||||||
let macro_definition = format!(" macro_rules! m {{ {} }} ", arm_definition);
|
let macro_definition = format!(" macro_rules! m {{ {} }} ", arm_definition);
|
||||||
let source_file = ast::SourceFile::parse(¯o_definition).ok().unwrap();
|
let source_file = ast::SourceFile::parse(¯o_definition).ok().unwrap();
|
||||||
let macro_definition =
|
let macro_definition =
|
||||||
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
|
||||||
|
|
||||||
let (definition_tt, _) =
|
let (definition_tt, _) =
|
||||||
ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap();
|
ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap();
|
||||||
|
@ -1668,7 +1668,7 @@ impl MacroFixture {
|
||||||
fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree {
|
fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree {
|
||||||
let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
|
let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
|
||||||
let macro_definition =
|
let macro_definition =
|
||||||
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
|
||||||
|
|
||||||
let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap();
|
let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,9 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
|
||||||
T![macro] => {
|
T![macro] => {
|
||||||
macro_def(p, m);
|
macro_def(p, m);
|
||||||
}
|
}
|
||||||
|
IDENT if p.at_contextual_kw("macro_rules") && p.nth(1) == BANG => {
|
||||||
|
macro_rules(p, m);
|
||||||
|
}
|
||||||
IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
|
IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
|
||||||
// test union_items
|
// test union_items
|
||||||
// union Foo {}
|
// union Foo {}
|
||||||
|
@ -363,6 +366,34 @@ pub(crate) fn item_list(p: &mut Parser) {
|
||||||
m.complete(p, ITEM_LIST);
|
m.complete(p, ITEM_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn macro_rules(p: &mut Parser, m: Marker) {
|
||||||
|
assert!(p.at_contextual_kw("macro_rules"));
|
||||||
|
p.bump_remap(T![macro_rules]);
|
||||||
|
p.expect(T![!]);
|
||||||
|
|
||||||
|
if p.at(IDENT) {
|
||||||
|
name(p);
|
||||||
|
}
|
||||||
|
// Special-case `macro_rules! try`.
|
||||||
|
// This is a hack until we do proper edition support
|
||||||
|
|
||||||
|
// test try_macro_rules
|
||||||
|
// macro_rules! try { () => {} }
|
||||||
|
if p.at(T![try]) {
|
||||||
|
let m = p.start();
|
||||||
|
p.bump_remap(IDENT);
|
||||||
|
m.complete(p, NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
match p.current() {
|
||||||
|
T!['{'] => {
|
||||||
|
token_tree(p);
|
||||||
|
}
|
||||||
|
_ => p.error("expected `{`"),
|
||||||
|
}
|
||||||
|
m.complete(p, MACRO_RULES);
|
||||||
|
}
|
||||||
|
|
||||||
// test macro_def
|
// test macro_def
|
||||||
// macro m { ($i:ident) => {} }
|
// macro m { ($i:ident) => {} }
|
||||||
// macro m($i:ident) {}
|
// macro m($i:ident) {}
|
||||||
|
@ -394,19 +425,6 @@ fn macro_call(p: &mut Parser) -> BlockLike {
|
||||||
|
|
||||||
pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
|
pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
|
||||||
p.expect(T![!]);
|
p.expect(T![!]);
|
||||||
if p.at(IDENT) {
|
|
||||||
name(p);
|
|
||||||
}
|
|
||||||
// Special-case `macro_rules! try`.
|
|
||||||
// This is a hack until we do proper edition support
|
|
||||||
|
|
||||||
// test try_macro_rules
|
|
||||||
// macro_rules! try { () => {} }
|
|
||||||
if p.at(T![try]) {
|
|
||||||
let m = p.start();
|
|
||||||
p.bump_remap(IDENT);
|
|
||||||
m.complete(p, NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
match p.current() {
|
match p.current() {
|
||||||
T!['{'] => {
|
T!['{'] => {
|
||||||
|
|
|
@ -106,6 +106,7 @@ pub enum SyntaxKind {
|
||||||
EXISTENTIAL_KW,
|
EXISTENTIAL_KW,
|
||||||
UNION_KW,
|
UNION_KW,
|
||||||
RAW_KW,
|
RAW_KW,
|
||||||
|
MACRO_RULES_KW,
|
||||||
INT_NUMBER,
|
INT_NUMBER,
|
||||||
FLOAT_NUMBER,
|
FLOAT_NUMBER,
|
||||||
CHAR,
|
CHAR,
|
||||||
|
@ -135,6 +136,8 @@ pub enum SyntaxKind {
|
||||||
IMPL,
|
IMPL,
|
||||||
TYPE_ALIAS,
|
TYPE_ALIAS,
|
||||||
MACRO_CALL,
|
MACRO_CALL,
|
||||||
|
MACRO_RULES,
|
||||||
|
MACRO_ARM,
|
||||||
TOKEN_TREE,
|
TOKEN_TREE,
|
||||||
MACRO_DEF,
|
MACRO_DEF,
|
||||||
PAREN_TYPE,
|
PAREN_TYPE,
|
||||||
|
@ -258,7 +261,7 @@ impl SyntaxKind {
|
||||||
| IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
|
| IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
|
||||||
| MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
|
| MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
|
||||||
| TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
|
| TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
|
||||||
| AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW => true,
|
| AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW | MACRO_RULES_KW => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,4 +364,4 @@ impl SyntaxKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [lifetime] => { $ crate :: SyntaxKind :: LIFETIME } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
|
macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime] => { $ crate :: SyntaxKind :: LIFETIME } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
|
||||||
|
|
|
@ -128,7 +128,6 @@ pub struct MacroCall {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
}
|
}
|
||||||
impl ast::AttrsOwner for MacroCall {}
|
impl ast::AttrsOwner for MacroCall {}
|
||||||
impl ast::NameOwner for MacroCall {}
|
|
||||||
impl MacroCall {
|
impl MacroCall {
|
||||||
pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
|
pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
|
||||||
pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
|
pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
|
||||||
|
@ -273,6 +272,20 @@ impl Impl {
|
||||||
pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
|
pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct MacroRules {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl ast::AttrsOwner for MacroRules {}
|
||||||
|
impl ast::NameOwner for MacroRules {}
|
||||||
|
impl ast::VisibilityOwner for MacroRules {}
|
||||||
|
impl MacroRules {
|
||||||
|
pub fn macro_rules_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![macro_rules])
|
||||||
|
}
|
||||||
|
pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
|
||||||
|
pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
}
|
}
|
||||||
|
@ -1318,6 +1331,7 @@ pub enum Item {
|
||||||
Fn(Fn),
|
Fn(Fn),
|
||||||
Impl(Impl),
|
Impl(Impl),
|
||||||
MacroCall(MacroCall),
|
MacroCall(MacroCall),
|
||||||
|
MacroRules(MacroRules),
|
||||||
Module(Module),
|
Module(Module),
|
||||||
Static(Static),
|
Static(Static),
|
||||||
Struct(Struct),
|
Struct(Struct),
|
||||||
|
@ -1374,7 +1388,6 @@ pub enum AssocItem {
|
||||||
TypeAlias(TypeAlias),
|
TypeAlias(TypeAlias),
|
||||||
}
|
}
|
||||||
impl ast::AttrsOwner for AssocItem {}
|
impl ast::AttrsOwner for AssocItem {}
|
||||||
impl ast::NameOwner for AssocItem {}
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ExternItem {
|
pub enum ExternItem {
|
||||||
Fn(Fn),
|
Fn(Fn),
|
||||||
|
@ -1383,7 +1396,6 @@ pub enum ExternItem {
|
||||||
TypeAlias(TypeAlias),
|
TypeAlias(TypeAlias),
|
||||||
}
|
}
|
||||||
impl ast::AttrsOwner for ExternItem {}
|
impl ast::AttrsOwner for ExternItem {}
|
||||||
impl ast::NameOwner for ExternItem {}
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum GenericParam {
|
pub enum GenericParam {
|
||||||
ConstParam(ConstParam),
|
ConstParam(ConstParam),
|
||||||
|
@ -1666,6 +1678,17 @@ impl AstNode for Impl {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for MacroRules {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for Module {
|
impl AstNode for Module {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -3060,6 +3083,9 @@ impl From<Impl> for Item {
|
||||||
impl From<MacroCall> for Item {
|
impl From<MacroCall> for Item {
|
||||||
fn from(node: MacroCall) -> Item { Item::MacroCall(node) }
|
fn from(node: MacroCall) -> Item { Item::MacroCall(node) }
|
||||||
}
|
}
|
||||||
|
impl From<MacroRules> for Item {
|
||||||
|
fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
|
||||||
|
}
|
||||||
impl From<Module> for Item {
|
impl From<Module> for Item {
|
||||||
fn from(node: Module) -> Item { Item::Module(node) }
|
fn from(node: Module) -> Item { Item::Module(node) }
|
||||||
}
|
}
|
||||||
|
@ -3084,8 +3110,8 @@ impl From<Use> for Item {
|
||||||
impl AstNode for Item {
|
impl AstNode for Item {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool {
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MODULE
|
CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
|
||||||
| STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
|
| MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3098,6 +3124,7 @@ impl AstNode for Item {
|
||||||
FN => Item::Fn(Fn { syntax }),
|
FN => Item::Fn(Fn { syntax }),
|
||||||
IMPL => Item::Impl(Impl { syntax }),
|
IMPL => Item::Impl(Impl { syntax }),
|
||||||
MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
|
MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
|
||||||
|
MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
|
||||||
MODULE => Item::Module(Module { syntax }),
|
MODULE => Item::Module(Module { syntax }),
|
||||||
STATIC => Item::Static(Static { syntax }),
|
STATIC => Item::Static(Static { syntax }),
|
||||||
STRUCT => Item::Struct(Struct { syntax }),
|
STRUCT => Item::Struct(Struct { syntax }),
|
||||||
|
@ -3118,6 +3145,7 @@ impl AstNode for Item {
|
||||||
Item::Fn(it) => &it.syntax,
|
Item::Fn(it) => &it.syntax,
|
||||||
Item::Impl(it) => &it.syntax,
|
Item::Impl(it) => &it.syntax,
|
||||||
Item::MacroCall(it) => &it.syntax,
|
Item::MacroCall(it) => &it.syntax,
|
||||||
|
Item::MacroRules(it) => &it.syntax,
|
||||||
Item::Module(it) => &it.syntax,
|
Item::Module(it) => &it.syntax,
|
||||||
Item::Static(it) => &it.syntax,
|
Item::Static(it) => &it.syntax,
|
||||||
Item::Struct(it) => &it.syntax,
|
Item::Struct(it) => &it.syntax,
|
||||||
|
@ -3582,6 +3610,11 @@ impl std::fmt::Display for Impl {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for MacroRules {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for Module {
|
impl std::fmt::Display for Module {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
|
|
@ -382,21 +382,6 @@ impl ast::Visibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::MacroCall {
|
|
||||||
pub fn is_macro_rules(&self) -> Option<ast::Name> {
|
|
||||||
let name_ref = self.path()?.segment()?.name_ref()?;
|
|
||||||
if name_ref.text() == "macro_rules" {
|
|
||||||
self.name()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_bang(&self) -> bool {
|
|
||||||
self.is_macro_rules().is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ast::LifetimeParam {
|
impl ast::LifetimeParam {
|
||||||
pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
|
pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
|
||||||
self.syntax()
|
self.syntax()
|
||||||
|
@ -476,5 +461,5 @@ impl ast::DocCommentsOwner for ast::Static {}
|
||||||
impl ast::DocCommentsOwner for ast::Const {}
|
impl ast::DocCommentsOwner for ast::Const {}
|
||||||
impl ast::DocCommentsOwner for ast::TypeAlias {}
|
impl ast::DocCommentsOwner for ast::TypeAlias {}
|
||||||
impl ast::DocCommentsOwner for ast::Impl {}
|
impl ast::DocCommentsOwner for ast::Impl {}
|
||||||
impl ast::DocCommentsOwner for ast::MacroCall {}
|
impl ast::DocCommentsOwner for ast::MacroRules {}
|
||||||
impl ast::DocCommentsOwner for ast::Use {}
|
impl ast::DocCommentsOwner for ast::Use {}
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub fn type_label(node: &ast::TypeAlias) -> String {
|
||||||
label.trim().to_owned()
|
label.trim().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn macro_label(node: &ast::MacroCall) -> String {
|
pub fn macro_label(node: &ast::MacroRules) -> String {
|
||||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
||||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
||||||
format!("{}macro_rules! {}", vis, name)
|
format!("{}macro_rules! {}", vis, name)
|
||||||
|
|
|
@ -147,8 +147,8 @@ fn n_attached_trivias<'a>(
|
||||||
trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
|
trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
match kind {
|
match kind {
|
||||||
MACRO_CALL | CONST | TYPE_ALIAS | STRUCT | ENUM | VARIANT | FN | TRAIT | MODULE
|
MACRO_CALL | MACRO_RULES | CONST | TYPE_ALIAS | STRUCT | ENUM | VARIANT | FN | TRAIT
|
||||||
| RECORD_FIELD | STATIC | USE => {
|
| MODULE | RECORD_FIELD | STATIC | USE => {
|
||||||
let mut res = 0;
|
let mut res = 0;
|
||||||
let mut trivias = trivias.enumerate().peekable();
|
let mut trivias = trivias.enumerate().peekable();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
mod block;
|
mod block;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algo, ast, match_ast, AstNode, SyntaxError,
|
algo,
|
||||||
|
ast::{self, VisibilityOwner},
|
||||||
|
match_ast, AstNode, SyntaxError,
|
||||||
SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
|
SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
|
||||||
SyntaxNode, SyntaxToken, TextSize, T,
|
SyntaxNode, SyntaxToken, TextSize, T,
|
||||||
};
|
};
|
||||||
|
@ -99,6 +101,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
|
||||||
ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
|
ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
|
||||||
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
|
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
|
||||||
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
|
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
|
||||||
|
ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,3 +353,12 @@ fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_macro_rules(mac: ast::MacroRules, errors: &mut Vec<SyntaxError>) {
|
||||||
|
if let Some(vis) = mac.visibility() {
|
||||||
|
errors.push(SyntaxError::new(
|
||||||
|
"visibilities are not allowed on `macro_rules!` items",
|
||||||
|
vis.syntax().text_range(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,14 +17,17 @@ SOURCE_FILE@0..42
|
||||||
IDENT@28..31 "bin"
|
IDENT@28..31 "bin"
|
||||||
ERROR@31..32
|
ERROR@31..32
|
||||||
SLASH@31..32 "/"
|
SLASH@31..32 "/"
|
||||||
MACRO_CALL@32..41
|
MACRO_CALL@32..35
|
||||||
PATH@32..35
|
PATH@32..35
|
||||||
PATH_SEGMENT@32..35
|
PATH_SEGMENT@32..35
|
||||||
NAME_REF@32..35
|
NAME_REF@32..35
|
||||||
IDENT@32..35 "env"
|
IDENT@32..35 "env"
|
||||||
WHITESPACE@35..36 " "
|
WHITESPACE@35..36 " "
|
||||||
NAME@36..41
|
MACRO_CALL@36..41
|
||||||
IDENT@36..41 "rusti"
|
PATH@36..41
|
||||||
|
PATH_SEGMENT@36..41
|
||||||
|
NAME_REF@36..41
|
||||||
|
IDENT@36..41 "rusti"
|
||||||
WHITESPACE@41..42 "\n"
|
WHITESPACE@41..42 "\n"
|
||||||
error 23..23: expected `[`
|
error 23..23: expected `[`
|
||||||
error 23..23: expected an item
|
error 23..23: expected an item
|
||||||
|
@ -35,5 +38,8 @@ error 31..31: expected `{`, `[`, `(`
|
||||||
error 31..31: expected SEMICOLON
|
error 31..31: expected SEMICOLON
|
||||||
error 31..31: expected an item
|
error 31..31: expected an item
|
||||||
error 35..35: expected BANG
|
error 35..35: expected BANG
|
||||||
|
error 35..35: expected `{`, `[`, `(`
|
||||||
|
error 35..35: expected SEMICOLON
|
||||||
|
error 41..41: expected BANG
|
||||||
error 41..41: expected `{`, `[`, `(`
|
error 41..41: expected `{`, `[`, `(`
|
||||||
error 41..41: expected SEMICOLON
|
error 41..41: expected SEMICOLON
|
||||||
|
|
|
@ -12,11 +12,8 @@ SOURCE_FILE@0..70
|
||||||
L_CURLY@9..10 "{"
|
L_CURLY@9..10 "{"
|
||||||
R_CURLY@10..11 "}"
|
R_CURLY@10..11 "}"
|
||||||
WHITESPACE@11..12 "\n"
|
WHITESPACE@11..12 "\n"
|
||||||
MACRO_CALL@12..31
|
MACRO_RULES@12..31
|
||||||
PATH@12..23
|
MACRO_RULES_KW@12..23 "macro_rules"
|
||||||
PATH_SEGMENT@12..23
|
|
||||||
NAME_REF@12..23
|
|
||||||
IDENT@12..23 "macro_rules"
|
|
||||||
BANG@23..24 "!"
|
BANG@23..24 "!"
|
||||||
WHITESPACE@24..25 " "
|
WHITESPACE@24..25 " "
|
||||||
NAME@25..28
|
NAME@25..28
|
||||||
|
|
|
@ -82,32 +82,28 @@ SOURCE_FILE@0..167
|
||||||
L_CURLY@102..103 "{"
|
L_CURLY@102..103 "{"
|
||||||
R_CURLY@103..104 "}"
|
R_CURLY@103..104 "}"
|
||||||
WHITESPACE@104..109 "\n "
|
WHITESPACE@104..109 "\n "
|
||||||
EXPR_STMT@109..152
|
MACRO_RULES@109..152
|
||||||
MACRO_CALL@109..152
|
MACRO_RULES_KW@109..120 "macro_rules"
|
||||||
PATH@109..120
|
BANG@120..121 "!"
|
||||||
PATH_SEGMENT@109..120
|
WHITESPACE@121..122 " "
|
||||||
NAME_REF@109..120
|
NAME@122..126
|
||||||
IDENT@109..120 "macro_rules"
|
IDENT@122..126 "test"
|
||||||
BANG@120..121 "!"
|
WHITESPACE@126..127 " "
|
||||||
WHITESPACE@121..122 " "
|
TOKEN_TREE@127..152
|
||||||
NAME@122..126
|
L_CURLY@127..128 "{"
|
||||||
IDENT@122..126 "test"
|
WHITESPACE@128..138 "\n "
|
||||||
WHITESPACE@126..127 " "
|
TOKEN_TREE@138..140
|
||||||
TOKEN_TREE@127..152
|
L_PAREN@138..139 "("
|
||||||
L_CURLY@127..128 "{"
|
R_PAREN@139..140 ")"
|
||||||
WHITESPACE@128..138 "\n "
|
WHITESPACE@140..141 " "
|
||||||
TOKEN_TREE@138..140
|
EQ@141..142 "="
|
||||||
L_PAREN@138..139 "("
|
R_ANGLE@142..143 ">"
|
||||||
R_PAREN@139..140 ")"
|
WHITESPACE@143..144 " "
|
||||||
WHITESPACE@140..141 " "
|
TOKEN_TREE@144..146
|
||||||
EQ@141..142 "="
|
L_CURLY@144..145 "{"
|
||||||
R_ANGLE@142..143 ">"
|
R_CURLY@145..146 "}"
|
||||||
WHITESPACE@143..144 " "
|
WHITESPACE@146..151 "\n "
|
||||||
TOKEN_TREE@144..146
|
R_CURLY@151..152 "}"
|
||||||
L_CURLY@144..145 "{"
|
|
||||||
R_CURLY@145..146 "}"
|
|
||||||
WHITESPACE@146..151 "\n "
|
|
||||||
R_CURLY@151..152 "}"
|
|
||||||
WHITESPACE@152..157 "\n "
|
WHITESPACE@152..157 "\n "
|
||||||
MACRO_CALL@157..164
|
MACRO_CALL@157..164
|
||||||
PATH@157..161
|
PATH@157..161
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
SOURCE_FILE@0..30
|
SOURCE_FILE@0..30
|
||||||
MACRO_CALL@0..29
|
MACRO_RULES@0..29
|
||||||
PATH@0..11
|
MACRO_RULES_KW@0..11 "macro_rules"
|
||||||
PATH_SEGMENT@0..11
|
|
||||||
NAME_REF@0..11
|
|
||||||
IDENT@0..11 "macro_rules"
|
|
||||||
BANG@11..12 "!"
|
BANG@11..12 "!"
|
||||||
WHITESPACE@12..13 " "
|
WHITESPACE@12..13 " "
|
||||||
NAME@13..16
|
NAME@13..16
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
SOURCE_FILE@0..65
|
SOURCE_FILE@0..65
|
||||||
MACRO_CALL@0..64
|
MACRO_RULES@0..64
|
||||||
COMMENT@0..13 "/// Some docs"
|
COMMENT@0..13 "/// Some docs"
|
||||||
WHITESPACE@13..14 "\n"
|
WHITESPACE@13..14 "\n"
|
||||||
ATTR@14..29
|
ATTR@14..29
|
||||||
|
@ -11,10 +11,7 @@ SOURCE_FILE@0..65
|
||||||
IDENT@16..28 "macro_export"
|
IDENT@16..28 "macro_export"
|
||||||
R_BRACK@28..29 "]"
|
R_BRACK@28..29 "]"
|
||||||
WHITESPACE@29..30 "\n"
|
WHITESPACE@29..30 "\n"
|
||||||
PATH@30..41
|
MACRO_RULES_KW@30..41 "macro_rules"
|
||||||
PATH_SEGMENT@30..41
|
|
||||||
NAME_REF@30..41
|
|
||||||
IDENT@30..41 "macro_rules"
|
|
||||||
BANG@41..42 "!"
|
BANG@41..42 "!"
|
||||||
WHITESPACE@42..43 " "
|
WHITESPACE@42..43 " "
|
||||||
NAME@43..46
|
NAME@43..46
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super",
|
"match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super",
|
||||||
"trait", "true", "try", "type", "unsafe", "use", "where", "while",
|
"trait", "true", "try", "type", "unsafe", "use", "where", "while",
|
||||||
],
|
],
|
||||||
contextual_keywords: &["auto", "default", "existential", "union", "raw"],
|
contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules"],
|
||||||
literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING"],
|
literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING"],
|
||||||
tokens: &[
|
tokens: &[
|
||||||
"ERROR",
|
"ERROR",
|
||||||
|
@ -98,6 +98,8 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"IMPL",
|
"IMPL",
|
||||||
"TYPE_ALIAS",
|
"TYPE_ALIAS",
|
||||||
"MACRO_CALL",
|
"MACRO_CALL",
|
||||||
|
"MACRO_RULES",
|
||||||
|
"MACRO_ARM",
|
||||||
"TOKEN_TREE",
|
"TOKEN_TREE",
|
||||||
"MACRO_DEF",
|
"MACRO_DEF",
|
||||||
"PAREN_TYPE",
|
"PAREN_TYPE",
|
||||||
|
|
Loading…
Reference in a new issue