Infallibe ExpandDatabase::macro_def

This commit is contained in:
Lukas Wirth 2023-07-10 16:23:29 +02:00
parent 4ff93398fd
commit d5f64f875a
10 changed files with 215 additions and 164 deletions

View file

@ -132,6 +132,7 @@ pub struct DeclarativeMacro {
// This is used for correctly determining the behavior of the pat fragment
// FIXME: This should be tracked by hygiene of the fragment identifier!
is_2021: bool,
err: Option<Box<ParseError>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -214,65 +215,100 @@ pub enum Origin {
}
impl DeclarativeMacro {
pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro {
DeclarativeMacro {
rules: Box::default(),
shift: Shift(0),
is_2021,
err: Some(Box::new(err)),
}
}
/// The old, `macro_rules! m {}` flavor.
pub fn parse_macro_rules(
tt: &tt::Subtree,
is_2021: bool,
) -> Result<DeclarativeMacro, ParseError> {
pub fn parse_macro_rules(tt: &tt::Subtree, is_2021: bool) -> DeclarativeMacro {
// Note: this parsing can be implemented using mbe machinery itself, by
// matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing
// manually seems easier.
let mut src = TtIter::new(tt);
let mut rules = Vec::new();
let mut err = None;
while src.len() > 0 {
let rule = Rule::parse(&mut src, true)?;
let rule = match Rule::parse(&mut src, true) {
Ok(it) => it,
Err(e) => {
err = Some(Box::new(e));
break;
}
};
rules.push(rule);
if let Err(()) = src.expect_char(';') {
if src.len() > 0 {
return Err(ParseError::expected("expected `;`"));
err = Some(Box::new(ParseError::expected("expected `;`")));
}
break;
}
}
for Rule { lhs, .. } in &rules {
validate(lhs)?;
if let Err(e) = validate(lhs) {
err = Some(Box::new(e));
break;
}
}
Ok(DeclarativeMacro { rules: rules.into_boxed_slice(), shift: Shift::new(tt), is_2021 })
DeclarativeMacro { rules: rules.into_boxed_slice(), shift: Shift::new(tt), is_2021, err }
}
/// The new, unstable `macro m {}` flavor.
pub fn parse_macro2(tt: &tt::Subtree, is_2021: bool) -> Result<DeclarativeMacro, ParseError> {
pub fn parse_macro2(tt: &tt::Subtree, is_2021: bool) -> DeclarativeMacro {
let mut src = TtIter::new(tt);
let mut rules = Vec::new();
let mut err = None;
if tt::DelimiterKind::Brace == tt.delimiter.kind {
cov_mark::hit!(parse_macro_def_rules);
while src.len() > 0 {
let rule = Rule::parse(&mut src, true)?;
let rule = match Rule::parse(&mut src, true) {
Ok(it) => it,
Err(e) => {
err = Some(Box::new(e));
break;
}
};
rules.push(rule);
if let Err(()) = src.expect_any_char(&[';', ',']) {
if src.len() > 0 {
return Err(ParseError::expected("expected `;` or `,` to delimit rules"));
err = Some(Box::new(ParseError::expected(
"expected `;` or `,` to delimit rules",
)));
}
break;
}
}
} else {
cov_mark::hit!(parse_macro_def_simple);
let rule = Rule::parse(&mut src, false)?;
if src.len() != 0 {
return Err(ParseError::expected("remaining tokens in macro def"));
match Rule::parse(&mut src, false) {
Ok(rule) => {
if src.len() != 0 {
err = Some(Box::new(ParseError::expected("remaining tokens in macro def")));
}
rules.push(rule);
}
Err(e) => {
err = Some(Box::new(e));
}
}
rules.push(rule);
}
for Rule { lhs, .. } in &rules {
validate(lhs)?;
if let Err(e) = validate(lhs) {
err = Some(Box::new(e));
break;
}
}
Ok(DeclarativeMacro { rules: rules.into_boxed_slice(), shift: Shift::new(tt), is_2021 })
DeclarativeMacro { rules: rules.into_boxed_slice(), shift: Shift::new(tt), is_2021, err }
}
pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
@ -282,6 +318,10 @@ impl DeclarativeMacro {
expander::expand_rules(&self.rules, &tt, self.is_2021)
}
pub fn err(&self) -> Option<&ParseError> {
self.err.as_deref()
}
pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
self.shift.shift(id)
}