Shrink mbe::ExpandError and mbe::ParseError

This commit is contained in:
Lukas Wirth 2022-02-03 17:25:24 +01:00
parent 2310908df7
commit 2ad71f1350
8 changed files with 78 additions and 92 deletions

View file

@ -368,7 +368,7 @@ fn compile_error_expand(
let text = it.text.as_str(); let text = it.text.as_str();
if text.starts_with('"') && text.ends_with('"') { if text.starts_with('"') && text.ends_with('"') {
// FIXME: does not handle raw strings // FIXME: does not handle raw strings
mbe::ExpandError::Other(text[1..text.len() - 1].to_string()) mbe::ExpandError::Other(text[1..text.len() - 1].into())
} else { } else {
mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()) mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into())
} }
@ -451,12 +451,12 @@ fn relative_file(
) -> Result<FileId, mbe::ExpandError> { ) -> Result<FileId, mbe::ExpandError> {
let call_site = call_id.as_file().original_file(db); let call_site = call_id.as_file().original_file(db);
let path = AnchoredPath { anchor: call_site, path: path_str }; let path = AnchoredPath { anchor: call_site, path: path_str };
let res = db let res = db.resolve_path(path).ok_or_else(|| {
.resolve_path(path) mbe::ExpandError::Other(format!("failed to load file `{path_str}`").into())
.ok_or_else(|| mbe::ExpandError::Other(format!("failed to load file `{}`", path_str)))?; })?;
// Prevent include itself // Prevent include itself
if res == call_site && !allow_recursion { if res == call_site && !allow_recursion {
Err(mbe::ExpandError::Other(format!("recursive inclusion of `{}`", path_str))) Err(mbe::ExpandError::Other(format!("recursive inclusion of `{path_str}`").into()))
} else { } else {
Ok(res) Ok(res)
} }

View file

@ -390,7 +390,7 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>,
MacroDefKind::BuiltInEager(..) => { MacroDefKind::BuiltInEager(..) => {
// FIXME: Return a random error here just to make the types align. // FIXME: Return a random error here just to make the types align.
// This obviously should do something real instead. // This obviously should do something real instead.
Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".to_string())) Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".into()))
} }
MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))), MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))),
} }

View file

@ -51,12 +51,12 @@ impl ProcMacroExpander {
{ {
ExpandResult { ExpandResult {
value: tt.clone(), value: tt.clone(),
err: Some(mbe::ExpandError::Other(text)), err: Some(mbe::ExpandError::Other(text.into())),
} }
} }
ProcMacroExpansionError::System(text) ProcMacroExpansionError::System(text)
| ProcMacroExpansionError::Panic(text) => { | ProcMacroExpansionError::Panic(text) => {
ExpandResult::only_err(mbe::ExpandError::Other(text)) ExpandResult::only_err(mbe::ExpandError::Other(text.into()))
} }
}, },
} }

View file

@ -88,15 +88,6 @@ impl Bindings {
} }
} }
macro_rules! err {
() => {
ExpandError::BindingError(format!(""))
};
($($tt:tt)*) => {
ExpandError::BindingError(format!($($tt)*))
};
}
#[derive(Clone, Debug, Default, PartialEq, Eq)] #[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(super) struct Match { pub(super) struct Match {
pub(super) bindings: Bindings, pub(super) bindings: Bindings,
@ -607,7 +598,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
src = it; src = it;
res.unmatched_tts += src.len(); res.unmatched_tts += src.len();
} }
res.add_err(err!("leftover tokens")); res.add_err(ExpandError::binding_error("leftover tokens"));
if let Some(error_reover_item) = error_recover_item { if let Some(error_reover_item) = error_recover_item {
res.bindings = bindings_builder.build(&error_reover_item); res.bindings = bindings_builder.build(&error_reover_item);
@ -664,10 +655,9 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
} }
fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> { fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> {
let rhs = match src.expect_leaf() { let rhs = src
Ok(l) => l, .expect_leaf()
Err(()) => return Err(err!("expected leaf: `{}`", lhs)), .map_err(|()| ExpandError::BindingError(format!("expected leaf: `{lhs}`").into()))?;
};
match (lhs, rhs) { match (lhs, rhs) {
( (
tt::Leaf::Punct(tt::Punct { char: lhs, .. }), tt::Leaf::Punct(tt::Punct { char: lhs, .. }),
@ -708,9 +698,13 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
"ident" => input "ident" => input
.expect_ident() .expect_ident()
.map(|ident| tt::Leaf::from(ident.clone()).into()) .map(|ident| tt::Leaf::from(ident.clone()).into())
.map_err(|()| err!("expected ident")), .map_err(|()| ExpandError::binding_error("expected ident")),
"tt" => input.expect_tt().map_err(|()| err!()), "tt" => input
"lifetime" => input.expect_lifetime().map_err(|()| err!("expected lifetime")), .expect_tt()
.map_err(|()| ExpandError::binding_error("expected token tree")),
"lifetime" => input
.expect_lifetime()
.map_err(|()| ExpandError::binding_error("expected lifetime")),
"literal" => { "literal" => {
let neg = input.eat_char('-'); let neg = input.eat_char('-');
input input
@ -725,7 +719,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
}), }),
} }
}) })
.map_err(|()| err!()) .map_err(|()| ExpandError::binding_error("expected literal"))
} }
_ => Err(ExpandError::UnexpectedToken), _ => Err(ExpandError::UnexpectedToken),
}; };

View file

@ -17,34 +17,32 @@ impl Bindings {
fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> { fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
macro_rules! binding_err { macro_rules! binding_err {
($($arg:tt)*) => { ExpandError::BindingError(format!($($arg)*)) }; ($($arg:tt)*) => { ExpandError::BindingError(format!($($arg)*).into()) };
} }
let mut b: &Binding = self let mut b: &Binding =
.inner self.inner.get(name).ok_or_else(|| binding_err!("could not find binding `{name}`"))?;
.get(name)
.ok_or_else(|| binding_err!("could not find binding `{}`", name))?;
for nesting_state in nesting.iter_mut() { for nesting_state in nesting.iter_mut() {
nesting_state.hit = true; nesting_state.hit = true;
b = match b { b = match b {
Binding::Fragment(_) => break, Binding::Fragment(_) => break,
Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| { Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
nesting_state.at_end = true; nesting_state.at_end = true;
binding_err!("could not find nested binding `{}`", name) binding_err!("could not find nested binding `{name}`")
})?, })?,
Binding::Empty => { Binding::Empty => {
nesting_state.at_end = true; nesting_state.at_end = true;
return Err(binding_err!("could not find empty binding `{}`", name)); return Err(binding_err!("could not find empty binding `{name}`"));
} }
}; };
} }
match b { match b {
Binding::Fragment(it) => Ok(it), Binding::Fragment(it) => Ok(it),
Binding::Nested(_) => { Binding::Nested(_) => {
Err(binding_err!("expected simple binding, found nested binding `{}`", name)) Err(binding_err!("expected simple binding, found nested binding `{name}`"))
} }
Binding::Empty => { Binding::Empty => {
Err(binding_err!("expected simple binding, found empty binding `{}`", name)) Err(binding_err!("expected simple binding, found empty binding `{name}`"))
} }
} }
} }
@ -180,7 +178,7 @@ fn expand_repeat(
); );
return ExpandResult { return ExpandResult {
value: Fragment::Tokens(Subtree::default().into()), value: Fragment::Tokens(Subtree::default().into()),
err: Some(ExpandError::Other("Expand exceed limit".to_string())), err: Some(ExpandError::Other("Expand exceed limit".into())),
}; };
} }

View file

@ -37,12 +37,22 @@ pub use crate::{
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum ParseError { pub enum ParseError {
UnexpectedToken(String), UnexpectedToken(Box<str>),
Expected(String), Expected(Box<str>),
InvalidRepeat, InvalidRepeat,
RepetitionEmptyTokenTree, RepetitionEmptyTokenTree,
} }
impl ParseError {
fn expected(e: &str) -> ParseError {
ParseError::Expected(e.into())
}
fn unexpected(e: &str) -> ParseError {
ParseError::UnexpectedToken(e.into())
}
}
impl fmt::Display for ParseError { impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
@ -58,11 +68,17 @@ impl fmt::Display for ParseError {
pub enum ExpandError { pub enum ExpandError {
NoMatchingRule, NoMatchingRule,
UnexpectedToken, UnexpectedToken,
BindingError(String), BindingError(Box<str>),
ConversionError, ConversionError,
// FIXME: no way mbe should know about proc macros. // FIXME: no way mbe should know about proc macros.
UnresolvedProcMacro, UnresolvedProcMacro,
Other(String), Other(Box<str>),
}
impl ExpandError {
fn binding_error(e: &str) -> ExpandError {
ExpandError::BindingError(e.into())
}
} }
impl fmt::Display for ExpandError { impl fmt::Display for ExpandError {
@ -107,10 +123,7 @@ impl Shift {
// Find the max token id inside a subtree // Find the max token id inside a subtree
fn max_id(subtree: &tt::Subtree) -> Option<u32> { fn max_id(subtree: &tt::Subtree) -> Option<u32> {
subtree let filter = |tt: &_| match tt {
.token_trees
.iter()
.filter_map(|tt| match tt {
tt::TokenTree::Subtree(subtree) => { tt::TokenTree::Subtree(subtree) => {
let tree_id = max_id(subtree); let tree_id = max_id(subtree);
match subtree.delimiter { match subtree.delimiter {
@ -127,8 +140,8 @@ impl Shift {
(id != tt::TokenId::unspecified()).then(|| id.0) (id != tt::TokenId::unspecified()).then(|| id.0)
} }
}) };
.max() subtree.token_trees.iter().filter_map(filter).max()
} }
} }
@ -183,7 +196,7 @@ impl DeclarativeMacro {
rules.push(rule); rules.push(rule);
if let Err(()) = src.expect_char(';') { if let Err(()) = src.expect_char(';') {
if src.len() > 0 { if src.len() > 0 {
return Err(ParseError::Expected("expected `;`".to_string())); return Err(ParseError::expected("expected `;`"));
} }
break; break;
} }
@ -208,9 +221,7 @@ impl DeclarativeMacro {
rules.push(rule); rules.push(rule);
if let Err(()) = src.expect_any_char(&[';', ',']) { if let Err(()) = src.expect_any_char(&[';', ',']) {
if src.len() > 0 { if src.len() > 0 {
return Err(ParseError::Expected( return Err(ParseError::expected("expected `;` or `,` to delimit rules"));
"expected `;` or `,` to delimit rules".to_string(),
));
} }
break; break;
} }
@ -219,7 +230,7 @@ impl DeclarativeMacro {
cov_mark::hit!(parse_macro_def_simple); cov_mark::hit!(parse_macro_def_simple);
let rule = Rule::parse(&mut src, false)?; let rule = Rule::parse(&mut src, false)?;
if src.len() != 0 { if src.len() != 0 {
return Err(ParseError::Expected("remaining tokens in macro def".to_string())); return Err(ParseError::expected("remaining tokens in macro def"));
} }
rules.push(rule); rules.push(rule);
} }
@ -256,16 +267,12 @@ impl DeclarativeMacro {
impl Rule { impl Rule {
fn parse(src: &mut TtIter, expect_arrow: bool) -> Result<Self, ParseError> { fn parse(src: &mut TtIter, expect_arrow: bool) -> Result<Self, ParseError> {
let lhs = src let lhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
.expect_subtree()
.map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
if expect_arrow { if expect_arrow {
src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?;
src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?;
} }
let rhs = src let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
.expect_subtree()
.map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
let lhs = MetaTemplate::parse_pattern(lhs)?; let lhs = MetaTemplate::parse_pattern(lhs)?;
let rhs = MetaTemplate::parse_template(rhs)?; let rhs = MetaTemplate::parse_template(rhs)?;
@ -325,7 +332,7 @@ impl<T> ExpandResult<T> {
where where
T: Default, T: Default,
{ {
Self::only_err(ExpandError::Other(err)) Self::only_err(ExpandError::Other(err.into()))
} }
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ExpandResult<U> { pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ExpandResult<U> {

View file

@ -104,12 +104,6 @@ enum Mode {
Template, Template,
} }
macro_rules! err {
($($tt:tt)*) => {
ParseError::UnexpectedToken(($($tt)*).to_string())
};
}
fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> { fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> {
let res = match first { let res = match first {
tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
@ -142,7 +136,7 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
Op::Var { name, kind, id } Op::Var { name, kind, id }
} }
tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => { tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => {
return Err(ParseError::Expected("ident".to_string())) return Err(ParseError::expected("expected ident"))
} }
}, },
} }
@ -158,8 +152,10 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<SmolStr>, ParseError> { fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<SmolStr>, ParseError> {
if let Mode::Pattern = mode { if let Mode::Pattern = mode {
src.expect_char(':').map_err(|()| err!("missing fragment specifier"))?; src.expect_char(':').map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
let ident = src.expect_ident().map_err(|()| err!("missing fragment specifier"))?; let ident = src
.expect_ident()
.map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
return Ok(Some(ident.text.clone())); return Ok(Some(ident.text.clone()));
}; };
Ok(None) Ok(None)

View file

@ -6,15 +6,6 @@ use tt::buffer::TokenBuffer;
use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult}; use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult};
macro_rules! err {
() => {
ExpandError::BindingError(format!(""))
};
($($tt:tt)*) => {
ExpandError::BindingError(format!($($tt)*))
};
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct TtIter<'a> { pub(crate) struct TtIter<'a> {
pub(crate) inner: std::slice::Iter<'a, tt::TokenTree>, pub(crate) inner: std::slice::Iter<'a, tt::TokenTree>,
@ -115,7 +106,7 @@ impl<'a> TtIter<'a> {
} }
let err = if error || !cursor.is_root() { let err = if error || !cursor.is_root() {
Some(err!("expected {:?}", entry_point)) Some(ExpandError::BindingError(format!("expected {entry_point:?}").into()))
} else { } else {
None None
}; };