internal: clean up code duplication
This commit is contained in:
parent
079e9fe496
commit
d4d67406d7
@ -28,10 +28,8 @@
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum TokenExpander {
|
pub enum TokenExpander {
|
||||||
/// Old-style `macro_rules`.
|
/// Old-style `macro_rules` or the new macros 2.0
|
||||||
MacroRules { mac: mbe::MacroRules, def_site_token_map: mbe::TokenMap },
|
DeclarativeMacro { mac: mbe::DeclarativeMacro, def_site_token_map: mbe::TokenMap },
|
||||||
/// AKA macros 2.0.
|
|
||||||
MacroDef { mac: mbe::MacroDef, def_site_token_map: mbe::TokenMap },
|
|
||||||
/// Stuff like `line!` and `file!`.
|
/// Stuff like `line!` and `file!`.
|
||||||
Builtin(BuiltinFnLikeExpander),
|
Builtin(BuiltinFnLikeExpander),
|
||||||
/// `global_allocator` and such.
|
/// `global_allocator` and such.
|
||||||
@ -50,8 +48,7 @@ fn expand(
|
|||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
) -> mbe::ExpandResult<tt::Subtree> {
|
) -> mbe::ExpandResult<tt::Subtree> {
|
||||||
match self {
|
match self {
|
||||||
TokenExpander::MacroRules { mac, .. } => mac.expand(tt),
|
TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt),
|
||||||
TokenExpander::MacroDef { mac, .. } => mac.expand(tt),
|
|
||||||
TokenExpander::Builtin(it) => it.expand(db, id, tt),
|
TokenExpander::Builtin(it) => it.expand(db, id, tt),
|
||||||
TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt),
|
TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt),
|
||||||
TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
|
TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
|
||||||
@ -66,8 +63,7 @@ fn expand(
|
|||||||
|
|
||||||
pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
|
pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
|
||||||
match self {
|
match self {
|
||||||
TokenExpander::MacroRules { mac, .. } => mac.map_id_down(id),
|
TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_down(id),
|
||||||
TokenExpander::MacroDef { mac, .. } => mac.map_id_down(id),
|
|
||||||
TokenExpander::Builtin(..)
|
TokenExpander::Builtin(..)
|
||||||
| TokenExpander::BuiltinAttr(..)
|
| TokenExpander::BuiltinAttr(..)
|
||||||
| TokenExpander::BuiltinDerive(..)
|
| TokenExpander::BuiltinDerive(..)
|
||||||
@ -77,8 +73,7 @@ pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
|
|||||||
|
|
||||||
pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
|
pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
|
||||||
match self {
|
match self {
|
||||||
TokenExpander::MacroRules { mac, .. } => mac.map_id_up(id),
|
TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_up(id),
|
||||||
TokenExpander::MacroDef { mac, .. } => mac.map_id_up(id),
|
|
||||||
TokenExpander::Builtin(..)
|
TokenExpander::Builtin(..)
|
||||||
| TokenExpander::BuiltinAttr(..)
|
| TokenExpander::BuiltinAttr(..)
|
||||||
| TokenExpander::BuiltinDerive(..)
|
| TokenExpander::BuiltinDerive(..)
|
||||||
@ -368,24 +363,27 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
|
|||||||
|
|
||||||
fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError> {
|
fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError> {
|
||||||
match id.kind {
|
match id.kind {
|
||||||
MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) {
|
MacroDefKind::Declarative(ast_id) => {
|
||||||
ast::Macro::MacroRules(macro_rules) => {
|
let (mac, def_site_token_map) = match ast_id.to_node(db) {
|
||||||
let arg = macro_rules
|
ast::Macro::MacroRules(macro_rules) => {
|
||||||
.token_tree()
|
let arg = macro_rules
|
||||||
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
|
.token_tree()
|
||||||
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
|
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
|
||||||
let mac = mbe::MacroRules::parse(&tt)?;
|
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
|
||||||
Ok(Arc::new(TokenExpander::MacroRules { mac, def_site_token_map }))
|
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt)?;
|
||||||
}
|
(mac, def_site_token_map)
|
||||||
ast::Macro::MacroDef(macro_def) => {
|
}
|
||||||
let arg = macro_def
|
ast::Macro::MacroDef(macro_def) => {
|
||||||
.body()
|
let arg = macro_def
|
||||||
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
|
.body()
|
||||||
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
|
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
|
||||||
let mac = mbe::MacroDef::parse(&tt)?;
|
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
|
||||||
Ok(Arc::new(TokenExpander::MacroDef { mac, def_site_token_map }))
|
let mac = mbe::DeclarativeMacro::parse_macro2(&tt)?;
|
||||||
}
|
(mac, def_site_token_map)
|
||||||
},
|
}
|
||||||
|
};
|
||||||
|
Ok(Arc::new(TokenExpander::DeclarativeMacro { mac, def_site_token_map }))
|
||||||
|
}
|
||||||
MacroDefKind::BuiltIn(expander, _) => Ok(Arc::new(TokenExpander::Builtin(expander))),
|
MacroDefKind::BuiltIn(expander, _) => Ok(Arc::new(TokenExpander::Builtin(expander))),
|
||||||
MacroDefKind::BuiltInAttr(expander, _) => {
|
MacroDefKind::BuiltInAttr(expander, _) => {
|
||||||
Ok(Arc::new(TokenExpander::BuiltinAttr(expander)))
|
Ok(Arc::new(TokenExpander::BuiltinAttr(expander)))
|
||||||
|
@ -160,11 +160,9 @@ fn map_ident_up(
|
|||||||
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
|
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
|
||||||
),
|
),
|
||||||
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def_start) {
|
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def_start) {
|
||||||
(
|
(TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => {
|
||||||
TokenExpander::MacroDef { def_site_token_map, .. }
|
(def_site_token_map, *tt)
|
||||||
| TokenExpander::MacroRules { def_site_token_map, .. },
|
}
|
||||||
Some(tt),
|
|
||||||
) => (def_site_token_map, *tt),
|
|
||||||
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
|
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -468,11 +468,9 @@ pub fn map_token_up(
|
|||||||
_ => match origin {
|
_ => match origin {
|
||||||
mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
|
mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
|
||||||
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
|
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
|
||||||
(
|
(TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => {
|
||||||
TokenExpander::MacroRules { def_site_token_map, .. }
|
(def_site_token_map, tt.syntax().cloned())
|
||||||
| TokenExpander::MacroDef { def_site_token_map, .. },
|
}
|
||||||
Some(tt),
|
|
||||||
) => (def_site_token_map, tt.syntax().cloned()),
|
|
||||||
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
|
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::{Op, RepeatKind, Separator},
|
parser::{Op, RepeatKind, Separator},
|
||||||
syntax_node_to_token_tree, MacroRules,
|
syntax_node_to_token_tree, DeclarativeMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -20,7 +20,7 @@ fn benchmark_parse_macro_rules() {
|
|||||||
let rules = macro_rules_fixtures_tt();
|
let rules = macro_rules_fixtures_tt();
|
||||||
let hash: usize = {
|
let hash: usize = {
|
||||||
let _pt = bench("mbe parse macro rules");
|
let _pt = bench("mbe parse macro rules");
|
||||||
rules.values().map(|it| MacroRules::parse(it).unwrap().rules.len()).sum()
|
rules.values().map(|it| DeclarativeMacro::parse_macro_rules(it).unwrap().rules.len()).sum()
|
||||||
};
|
};
|
||||||
assert_eq!(hash, 1144);
|
assert_eq!(hash, 1144);
|
||||||
}
|
}
|
||||||
@ -47,10 +47,10 @@ fn benchmark_expand_macro_rules() {
|
|||||||
assert_eq!(hash, 69413);
|
assert_eq!(hash, 69413);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macro_rules_fixtures() -> FxHashMap<String, MacroRules> {
|
fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
|
||||||
macro_rules_fixtures_tt()
|
macro_rules_fixtures_tt()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, tt)| (id, MacroRules::parse(&tt).unwrap()))
|
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt).unwrap()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate random invocation fixtures from rules
|
/// Generate random invocation fixtures from rules
|
||||||
fn invocation_fixtures(rules: &FxHashMap<String, MacroRules>) -> Vec<(String, tt::Subtree)> {
|
fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(String, tt::Subtree)> {
|
||||||
let mut seed = 123456789;
|
let mut seed = 123456789;
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
@ -83,15 +83,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
|
/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
|
||||||
/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
|
/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct MacroRules {
|
pub struct DeclarativeMacro {
|
||||||
rules: Vec<Rule>,
|
|
||||||
/// Highest id of the token we have in TokenMap
|
|
||||||
shift: Shift,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For Macro 2.0
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct MacroDef {
|
|
||||||
rules: Vec<Rule>,
|
rules: Vec<Rule>,
|
||||||
/// Highest id of the token we have in TokenMap
|
/// Highest id of the token we have in TokenMap
|
||||||
shift: Shift,
|
shift: Shift,
|
||||||
@ -176,8 +168,9 @@ pub enum Origin {
|
|||||||
Call,
|
Call,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacroRules {
|
impl DeclarativeMacro {
|
||||||
pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> {
|
/// The old, `macro_rules! m {}` flavor.
|
||||||
|
pub fn parse_macro_rules(tt: &tt::Subtree) -> Result<DeclarativeMacro, ParseError> {
|
||||||
// Note: this parsing can be implemented using mbe machinery itself, by
|
// Note: this parsing can be implemented using mbe machinery itself, by
|
||||||
// matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing
|
// matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing
|
||||||
// manually seems easier.
|
// manually seems easier.
|
||||||
@ -198,30 +191,11 @@ pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> {
|
|||||||
validate(&rule.lhs)?;
|
validate(&rule.lhs)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(MacroRules { rules, shift: Shift::new(tt) })
|
Ok(DeclarativeMacro { rules, shift: Shift::new(tt) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
|
/// The new, unstable `macro m {}` flavor.
|
||||||
// apply shift
|
pub fn parse_macro2(tt: &tt::Subtree) -> Result<DeclarativeMacro, ParseError> {
|
||||||
let mut tt = tt.clone();
|
|
||||||
self.shift.shift_all(&mut tt);
|
|
||||||
expander::expand_rules(&self.rules, &tt)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
|
|
||||||
self.shift.shift(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, Origin) {
|
|
||||||
match self.shift.unshift(id) {
|
|
||||||
Some(id) => (id, Origin::Call),
|
|
||||||
None => (id, Origin::Def),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MacroDef {
|
|
||||||
pub fn parse(tt: &tt::Subtree) -> Result<MacroDef, ParseError> {
|
|
||||||
let mut src = TtIter::new(tt);
|
let mut src = TtIter::new(tt);
|
||||||
let mut rules = Vec::new();
|
let mut rules = Vec::new();
|
||||||
|
|
||||||
@ -251,7 +225,7 @@ pub fn parse(tt: &tt::Subtree) -> Result<MacroDef, ParseError> {
|
|||||||
validate(&rule.lhs)?;
|
validate(&rule.lhs)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(MacroDef { rules, shift: Shift::new(tt) })
|
Ok(DeclarativeMacro { rules, shift: Shift::new(tt) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
|
pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
|
||||||
|
Loading…
Reference in New Issue
Block a user