mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Shrink mbe::ExpandError
and mbe::ParseError
This commit is contained in:
parent
2310908df7
commit
2ad71f1350
8 changed files with 78 additions and 92 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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())),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue