Unnamed repository; edit this file 'description' to name the repository.
Merge #10431
10431: internal: cleanup mbe a bit r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
bors[bot] 2021-10-03
parent e504f8a · parent 4e35227 · commit 60c5449
-rw-r--r--crates/mbe/src/expander/matcher.rs60
-rw-r--r--crates/mbe/src/lib.rs6
-rw-r--r--crates/mbe/src/parser.rs113
3 files changed, 95 insertions, 84 deletions
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 7d8f97c775..06c21dfd70 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -63,7 +63,7 @@ use std::rc::Rc;
use crate::{
expander::{Binding, Bindings, Fragment},
- parser::{Op, OpDelimited, OpDelimitedIter, RepeatKind, Separator},
+ parser::{Op, RepeatKind, Separator},
tt_iter::TtIter,
ExpandError, MetaTemplate,
};
@@ -750,6 +750,64 @@ fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) {
}
}
+impl MetaTemplate {
+ fn iter_delimited<'a>(&'a self, delimited: Option<&'a tt::Delimiter>) -> OpDelimitedIter<'a> {
+ OpDelimitedIter { inner: &self.0, idx: 0, delimited }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum OpDelimited<'a> {
+ Op(&'a Op),
+ Open,
+ Close,
+}
+
+#[derive(Debug, Clone, Copy)]
+struct OpDelimitedIter<'a> {
+ inner: &'a [Op],
+ delimited: Option<&'a tt::Delimiter>,
+ idx: usize,
+}
+
+impl<'a> OpDelimitedIter<'a> {
+ fn is_eof(&self) -> bool {
+ let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
+ self.idx >= len
+ }
+
+ fn peek(&self) -> Option<OpDelimited<'a>> {
+ match self.delimited {
+ None => self.inner.get(self.idx).map(OpDelimited::Op),
+ Some(_) => match self.idx {
+ 0 => Some(OpDelimited::Open),
+ i if i == self.inner.len() + 1 => Some(OpDelimited::Close),
+ i => self.inner.get(i - 1).map(OpDelimited::Op),
+ },
+ }
+ }
+
+ fn reset(&self) -> Self {
+ Self { inner: self.inner, idx: 0, delimited: self.delimited }
+ }
+}
+
+impl<'a> Iterator for OpDelimitedIter<'a> {
+ type Item = OpDelimited<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let res = self.peek();
+ self.idx += 1;
+ res
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
+ let remain = len.saturating_sub(self.idx);
+ (remain, Some(remain))
+ }
+}
+
impl<'a> TtIter<'a> {
fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool {
let mut fork = self.clone();
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 0a1b7cc848..8470ea0aaf 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -19,7 +19,7 @@ mod token_map;
use std::fmt;
use crate::{
- parser::{parse_pattern, parse_template, MetaTemplate, Op},
+ parser::{MetaTemplate, Op},
tt_iter::TtIter,
};
@@ -275,8 +275,8 @@ impl Rule {
.expect_subtree()
.map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
- let lhs = MetaTemplate(parse_pattern(lhs)?);
- let rhs = MetaTemplate(parse_template(rhs)?);
+ let lhs = MetaTemplate::parse_pattern(lhs)?;
+ let rhs = MetaTemplate::parse_template(rhs)?;
Ok(crate::Rule { lhs, rhs })
}
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index deed884d2d..4ce818f9b0 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -3,75 +3,48 @@
use smallvec::SmallVec;
use syntax::SmolStr;
-use tt::Delimiter;
use crate::{tt_iter::TtIter, ParseError};
+/// Consider
+///
+/// ```
+/// macro_rules! an_macro {
+/// ($x:expr + $y:expr) => ($y * $x)
+/// }
+/// ```
+///
+/// Stuff to the left of `=>` is a [`MetaTemplate`] pattern (which is matched
+/// with input).
+///
+/// Stuff to the right is a [`MetaTemplate`] template which is used to produce
+/// output.
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct MetaTemplate(pub(crate) Vec<Op>);
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum OpDelimited<'a> {
- Op(&'a Op),
- Open,
- Close,
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct OpDelimitedIter<'a> {
- inner: &'a Vec<Op>,
- delimited: Option<&'a Delimiter>,
- idx: usize,
-}
-
-impl<'a> OpDelimitedIter<'a> {
- pub(crate) fn is_eof(&self) -> bool {
- let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
- self.idx >= len
- }
-
- pub(crate) fn peek(&self) -> Option<OpDelimited<'a>> {
- match self.delimited {
- None => self.inner.get(self.idx).map(OpDelimited::Op),
- Some(_) => match self.idx {
- 0 => Some(OpDelimited::Open),
- i if i == self.inner.len() + 1 => Some(OpDelimited::Close),
- i => self.inner.get(i - 1).map(OpDelimited::Op),
- },
- }
- }
-
- pub(crate) fn reset(&self) -> Self {
- Self { inner: self.inner, idx: 0, delimited: self.delimited }
+impl MetaTemplate {
+ pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<MetaTemplate, ParseError> {
+ MetaTemplate::parse(pattern, Mode::Pattern)
}
-}
-
-impl<'a> Iterator for OpDelimitedIter<'a> {
- type Item = OpDelimited<'a>;
- fn next(&mut self) -> Option<Self::Item> {
- let res = self.peek();
- self.idx += 1;
- res
+ pub(crate) fn parse_template(template: &tt::Subtree) -> Result<MetaTemplate, ParseError> {
+ MetaTemplate::parse(template, Mode::Template)
}
- fn size_hint(&self) -> (usize, Option<usize>) {
- let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
- let remain = len.saturating_sub(self.idx);
- (remain, Some(remain))
- }
-}
-
-impl<'a> MetaTemplate {
pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> {
self.0.iter()
}
- pub(crate) fn iter_delimited(
- &'a self,
- delimited: Option<&'a Delimiter>,
- ) -> OpDelimitedIter<'a> {
- OpDelimitedIter { inner: &self.0, idx: 0, delimited }
+ fn parse(tt: &tt::Subtree, mode: Mode) -> Result<MetaTemplate, ParseError> {
+ let mut src = TtIter::new(tt);
+
+ let mut res = Vec::new();
+ while let Some(first) = src.next() {
+ let op = next_op(first, &mut src, mode)?;
+ res.push(op)
+ }
+
+ Ok(MetaTemplate(res))
}
}
@@ -80,7 +53,7 @@ pub(crate) enum Op {
Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId },
Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
Leaf(tt::Leaf),
- Subtree { tokens: MetaTemplate, delimiter: Option<Delimiter> },
+ Subtree { tokens: MetaTemplate, delimiter: Option<tt::Delimiter> },
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -125,29 +98,12 @@ impl Separator {
}
}
-pub(crate) fn parse_template(template: &tt::Subtree) -> Result<Vec<Op>, ParseError> {
- parse_inner(template, Mode::Template).into_iter().collect()
-}
-
-pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<Vec<Op>, ParseError> {
- parse_inner(pattern, Mode::Pattern).into_iter().collect()
-}
-
#[derive(Clone, Copy)]
enum Mode {
Pattern,
Template,
}
-fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ParseError>> {
- let mut src = TtIter::new(tt);
- std::iter::from_fn(move || {
- let first = src.next()?;
- Some(next_op(first, &mut src, mode))
- })
- .collect()
-}
-
macro_rules! err {
($($tt:tt)*) => {
ParseError::UnexpectedToken(($($tt)*).to_string())
@@ -171,10 +127,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
match second {
tt::TokenTree::Subtree(subtree) => {
let (separator, kind) = parse_repeat(src)?;
- let tokens = parse_inner(subtree, mode)
- .into_iter()
- .collect::<Result<Vec<Op>, ParseError>>()?;
- Op::Repeat { tokens: MetaTemplate(tokens), separator, kind }
+ let tokens = MetaTemplate::parse(subtree, mode)?;
+ Op::Repeat { tokens, separator, kind }
}
tt::TokenTree::Leaf(leaf) => match leaf {
tt::Leaf::Punct(_) => {
@@ -205,9 +159,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
}
tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()),
tt::TokenTree::Subtree(subtree) => {
- let tokens =
- parse_inner(subtree, mode).into_iter().collect::<Result<Vec<Op>, ParseError>>()?;
- Op::Subtree { tokens: MetaTemplate(tokens), delimiter: subtree.delimiter }
+ let tokens = MetaTemplate::parse(subtree, mode)?;
+ Op::Subtree { tokens, delimiter: subtree.delimiter }
}
};
Ok(res)