aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src/parser.rs')
-rw-r--r--crates/mbe/src/parser.rs68
1 files changed, 34 insertions, 34 deletions
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index d681905f5..2f3ebc831 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -4,16 +4,17 @@
4use smallvec::SmallVec; 4use smallvec::SmallVec;
5use syntax::SmolStr; 5use syntax::SmolStr;
6 6
7use crate::{tt_iter::TtIter, ExpandError}; 7use crate::{tt_iter::TtIter, ExpandError, MetaTemplate};
8 8
9#[derive(Debug)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub(crate) enum Op<'a> { 10pub(crate) enum Op {
11 Var { name: &'a SmolStr, kind: Option<&'a SmolStr> }, 11 Var { name: SmolStr, kind: Option<SmolStr> },
12 Repeat { subtree: &'a tt::Subtree, kind: RepeatKind, separator: Option<Separator> }, 12 Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
13 TokenTree(&'a tt::TokenTree), 13 Leaf(tt::Leaf),
14 Subtree(MetaTemplate),
14} 15}
15 16
16#[derive(Clone, Debug, PartialEq, Eq)] 17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17pub(crate) enum RepeatKind { 18pub(crate) enum RepeatKind {
18 ZeroOrMore, 19 ZeroOrMore,
19 OneOrMore, 20 OneOrMore,
@@ -45,16 +46,12 @@ impl PartialEq for Separator {
45 } 46 }
46} 47}
47 48
48pub(crate) fn parse_template( 49pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> {
49 template: &tt::Subtree, 50 parse_inner(&template, Mode::Template)
50) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
51 parse_inner(template, Mode::Template)
52} 51}
53 52
54pub(crate) fn parse_pattern( 53pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> {
55 pattern: &tt::Subtree, 54 parse_inner(&pattern, Mode::Pattern)
56) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
57 parse_inner(pattern, Mode::Pattern)
58} 55}
59 56
60#[derive(Clone, Copy)] 57#[derive(Clone, Copy)]
@@ -63,12 +60,13 @@ enum Mode {
63 Template, 60 Template,
64} 61}
65 62
66fn parse_inner(src: &tt::Subtree, mode: Mode) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { 63fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> {
67 let mut src = TtIter::new(src); 64 let mut src = TtIter::new(&tt);
68 std::iter::from_fn(move || { 65 std::iter::from_fn(move || {
69 let first = src.next()?; 66 let first = src.next()?;
70 Some(next_op(first, &mut src, mode)) 67 Some(next_op(first, &mut src, mode))
71 }) 68 })
69 .collect()
72} 70}
73 71
74macro_rules! err { 72macro_rules! err {
@@ -83,21 +81,20 @@ macro_rules! bail {
83 }; 81 };
84} 82}
85 83
86fn next_op<'a>( 84fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> {
87 first: &'a tt::TokenTree,
88 src: &mut TtIter<'a>,
89 mode: Mode,
90) -> Result<Op<'a>, ExpandError> {
91 let res = match first { 85 let res = match first {
92 tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { 86 tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
93 // Note that the '$' itself is a valid token inside macro_rules. 87 // Note that the '$' itself is a valid token inside macro_rules.
94 let second = match src.next() { 88 let second = match src.next() {
95 None => return Ok(Op::TokenTree(first)), 89 None => return Ok(Op::Leaf(leaf.clone())),
96 Some(it) => it, 90 Some(it) => it,
97 }; 91 };
98 match second { 92 match second {
99 tt::TokenTree::Subtree(subtree) => { 93 tt::TokenTree::Subtree(subtree) => {
100 let (separator, kind) = parse_repeat(src)?; 94 let (separator, kind) = parse_repeat(src)?;
95 let delimiter = subtree.delimiter;
96 let tokens = parse_inner(&subtree, mode);
97 let subtree = MetaTemplate { tokens, delimiter };
101 Op::Repeat { subtree, separator, kind } 98 Op::Repeat { subtree, separator, kind }
102 } 99 }
103 tt::TokenTree::Leaf(leaf) => match leaf { 100 tt::TokenTree::Leaf(leaf) => match leaf {
@@ -107,18 +104,18 @@ fn next_op<'a>(
107 if punct.char != '_' { 104 if punct.char != '_' {
108 return Err(ExpandError::UnexpectedToken); 105 return Err(ExpandError::UnexpectedToken);
109 } 106 }
110 let name = &UNDERSCORE; 107 let name = UNDERSCORE.clone();
111 let kind = eat_fragment_kind(src, mode)?; 108 let kind = eat_fragment_kind(src, mode)?;
112 Op::Var { name, kind } 109 Op::Var { name, kind }
113 } 110 }
114 tt::Leaf::Ident(ident) => { 111 tt::Leaf::Ident(ident) => {
115 let name = &ident.text; 112 let name = ident.text.clone();
116 let kind = eat_fragment_kind(src, mode)?; 113 let kind = eat_fragment_kind(src, mode)?;
117 Op::Var { name, kind } 114 Op::Var { name, kind }
118 } 115 }
119 tt::Leaf::Literal(lit) => { 116 tt::Leaf::Literal(lit) => {
120 if is_boolean_literal(lit) { 117 if is_boolean_literal(&lit) {
121 let name = &lit.text; 118 let name = lit.text.clone();
122 let kind = eat_fragment_kind(src, mode)?; 119 let kind = eat_fragment_kind(src, mode)?;
123 Op::Var { name, kind } 120 Op::Var { name, kind }
124 } else { 121 } else {
@@ -128,19 +125,22 @@ fn next_op<'a>(
128 }, 125 },
129 } 126 }
130 } 127 }
131 tt => Op::TokenTree(tt), 128 tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()),
129 tt::TokenTree::Subtree(subtree) => {
130 let delimiter = subtree.delimiter;
131 let tokens = parse_inner(&subtree, mode);
132 let subtree = MetaTemplate { tokens, delimiter };
133 Op::Subtree(subtree)
134 }
132 }; 135 };
133 Ok(res) 136 Ok(res)
134} 137}
135 138
136fn eat_fragment_kind<'a>( 139fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> {
137 src: &mut TtIter<'a>,
138 mode: Mode,
139) -> Result<Option<&'a SmolStr>, ExpandError> {
140 if let Mode::Pattern = mode { 140 if let Mode::Pattern = mode {
141 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; 141 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?;
142 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; 142 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?;
143 return Ok(Some(&ident.text)); 143 return Ok(Some(ident.text.clone()));
144 }; 144 };
145 Ok(None) 145 Ok(None)
146} 146}