aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2020-12-29 18:35:21 +0000
committerEdwin Cheng <[email protected]>2020-12-29 18:51:06 +0000
commit266b14d4b5b44d1491e50c7aa2ed4b85020796e1 (patch)
treee5a76f841673e063538eb2a590d4233d5a5e5d11 /crates
parent77ad203a719be074e81485af7a4fb02fac6cbf61 (diff)
Refactor mbe parsing code
Diffstat (limited to 'crates')
-rw-r--r--crates/mbe/src/lib.rs46
-rw-r--r--crates/mbe/src/mbe_expander/matcher.rs32
-rw-r--r--crates/mbe/src/mbe_expander/transcriber.rs29
-rw-r--r--crates/mbe/src/parser.rs68
4 files changed, 99 insertions, 76 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 3ad609a00..7878faaa4 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -14,10 +14,10 @@ mod tests;
14 14
15use std::fmt; 15use std::fmt;
16 16
17pub use tt::{Delimiter, Punct}; 17pub use tt::{Delimiter, DelimiterKind, Punct};
18 18
19use crate::{ 19use crate::{
20 parser::{parse_pattern, Op}, 20 parser::{parse_pattern, parse_template, Op},
21 tt_iter::TtIter, 21 tt_iter::TtIter,
22}; 22};
23 23
@@ -78,8 +78,24 @@ pub struct MacroRules {
78 78
79#[derive(Clone, Debug, PartialEq, Eq)] 79#[derive(Clone, Debug, PartialEq, Eq)]
80struct Rule { 80struct Rule {
81 lhs: tt::Subtree, 81 lhs: MetaTemplate,
82 rhs: tt::Subtree, 82 rhs: MetaTemplate,
83}
84
85#[derive(Clone, Debug, PartialEq, Eq)]
86struct MetaTemplate {
87 delimiter: Option<Delimiter>,
88 tokens: Vec<Result<Op, ExpandError>>,
89}
90
91impl<'a> MetaTemplate {
92 fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> {
93 self.tokens.iter()
94 }
95
96 fn delimiter_kind(&self) -> Option<DelimiterKind> {
97 self.delimiter.map(|it| it.kind)
98 }
83} 99}
84 100
85#[derive(Clone, Copy, Debug, PartialEq, Eq)] 101#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -167,7 +183,7 @@ impl MacroRules {
167 rules.push(rule); 183 rules.push(rule);
168 if let Err(()) = src.expect_char(';') { 184 if let Err(()) = src.expect_char(';') {
169 if src.len() > 0 { 185 if src.len() > 0 {
170 return Err(ParseError::Expected("expected `:`".to_string())); 186 return Err(ParseError::Expected("expected `;`".to_string()));
171 } 187 }
172 break; 188 break;
173 } 189 }
@@ -213,11 +229,15 @@ impl Rule {
213 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 229 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
214 .clone(); 230 .clone();
215 rhs.delimiter = None; 231 rhs.delimiter = None;
232
233 let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None };
234 let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None };
235
216 Ok(crate::Rule { lhs, rhs }) 236 Ok(crate::Rule { lhs, rhs })
217 } 237 }
218} 238}
219 239
220fn to_parse_error(e: ExpandError) -> ParseError { 240fn to_parse_error(e: &ExpandError) -> ParseError {
221 let msg = match e { 241 let msg = match e {
222 ExpandError::InvalidRepeat => "invalid repeat".to_string(), 242 ExpandError::InvalidRepeat => "invalid repeat".to_string(),
223 _ => "invalid macro definition".to_string(), 243 _ => "invalid macro definition".to_string(),
@@ -225,22 +245,22 @@ fn to_parse_error(e: ExpandError) -> ParseError {
225 ParseError::Expected(msg) 245 ParseError::Expected(msg)
226} 246}
227 247
228fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { 248fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
229 for op in parse_pattern(pattern) { 249 for op in pattern.iter() {
230 let op = op.map_err(to_parse_error)?; 250 let op = op.as_ref().map_err(|e| to_parse_error(&e))?;
231 251
232 match op { 252 match op {
233 Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?, 253 Op::Subtree(subtree) => validate(&subtree)?,
234 Op::Repeat { subtree, separator, .. } => { 254 Op::Repeat { subtree, separator, .. } => {
235 // Checks that no repetition which could match an empty token 255 // Checks that no repetition which could match an empty token
236 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 256 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558
237 257
238 if separator.is_none() { 258 if separator.is_none() {
239 if parse_pattern(subtree).all(|child_op| { 259 if subtree.iter().all(|child_op| {
240 match child_op.map_err(to_parse_error) { 260 match child_op.as_ref().map_err(to_parse_error) {
241 Ok(Op::Var { kind, .. }) => { 261 Ok(Op::Var { kind, .. }) => {
242 // vis is optional 262 // vis is optional
243 if kind.map_or(false, |it| it == "vis") { 263 if kind.as_ref().map_or(false, |it| it == "vis") {
244 return true; 264 return true;
245 } 265 }
246 } 266 }
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index 44722c0f1..ab5f87c48 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -2,10 +2,10 @@
2 2
3use crate::{ 3use crate::{
4 mbe_expander::{Binding, Bindings, Fragment}, 4 mbe_expander::{Binding, Bindings, Fragment},
5 parser::{parse_pattern, Op, RepeatKind, Separator}, 5 parser::{Op, RepeatKind, Separator},
6 subtree_source::SubtreeTokenSource, 6 subtree_source::SubtreeTokenSource,
7 tt_iter::TtIter, 7 tt_iter::TtIter,
8 ExpandError, 8 ExpandError, MetaTemplate,
9}; 9};
10 10
11use super::ExpandResult; 11use super::ExpandResult;
@@ -83,7 +83,7 @@ impl Match {
83// sense to try using it. Matching errors are added to the `Match`. It might 83// sense to try using it. Matching errors are added to the `Match`. It might
84// make sense to make pattern parsing a separate step? 84// make sense to make pattern parsing a separate step?
85 85
86pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> { 86pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> {
87 assert!(pattern.delimiter == None); 87 assert!(pattern.delimiter == None);
88 88
89 let mut res = Match::default(); 89 let mut res = Match::default();
@@ -101,12 +101,12 @@ pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match,
101 101
102fn match_subtree( 102fn match_subtree(
103 res: &mut Match, 103 res: &mut Match,
104 pattern: &tt::Subtree, 104 pattern: &MetaTemplate,
105 src: &mut TtIter, 105 src: &mut TtIter,
106) -> Result<(), ExpandError> { 106) -> Result<(), ExpandError> {
107 for op in parse_pattern(pattern) { 107 for op in pattern.iter() {
108 match op? { 108 match op.as_ref().map_err(|err| err.clone())? {
109 Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { 109 Op::Leaf(lhs) => {
110 let rhs = match src.expect_leaf() { 110 let rhs = match src.expect_leaf() {
111 Ok(l) => l, 111 Ok(l) => l,
112 Err(()) => { 112 Err(()) => {
@@ -132,7 +132,7 @@ fn match_subtree(
132 } 132 }
133 } 133 }
134 } 134 }
135 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { 135 Op::Subtree(lhs) => {
136 let rhs = match src.expect_subtree() { 136 let rhs = match src.expect_subtree() {
137 Ok(s) => s, 137 Ok(s) => s,
138 Err(()) => { 138 Err(()) => {
@@ -172,7 +172,7 @@ fn match_subtree(
172 } 172 }
173 } 173 }
174 Op::Repeat { subtree, kind, separator } => { 174 Op::Repeat { subtree, kind, separator } => {
175 match_repeat(res, subtree, kind, separator, src)?; 175 match_repeat(res, subtree, *kind, separator, src)?;
176 } 176 }
177 } 177 }
178 } 178 }
@@ -372,9 +372,9 @@ impl<'a> TtIter<'a> {
372 372
373pub(super) fn match_repeat( 373pub(super) fn match_repeat(
374 res: &mut Match, 374 res: &mut Match,
375 pattern: &tt::Subtree, 375 pattern: &MetaTemplate,
376 kind: RepeatKind, 376 kind: RepeatKind,
377 separator: Option<Separator>, 377 separator: &Option<Separator>,
378 src: &mut TtIter, 378 src: &mut TtIter,
379) -> Result<(), ExpandError> { 379) -> Result<(), ExpandError> {
380 // Dirty hack to make macro-expansion terminate. 380 // Dirty hack to make macro-expansion terminate.
@@ -489,12 +489,12 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
489 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) 489 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
490} 490}
491 491
492fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { 492fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) -> Result<(), ExpandError> {
493 for op in parse_pattern(pattern) { 493 for op in pattern.iter() {
494 match op? { 494 match op.as_ref().map_err(|e| e.clone())? {
495 Op::Var { name, .. } => buf.push(name.clone()), 495 Op::Var { name, .. } => buf.push(name.clone()),
496 Op::TokenTree(tt::TokenTree::Leaf(_)) => (), 496 Op::Leaf(_) => (),
497 Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?, 497 Op::Subtree(subtree) => collect_vars(buf, subtree)?,
498 Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, 498 Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?,
499 } 499 }
500 } 500 }
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs
index 57592dc92..720531237 100644
--- a/crates/mbe/src/mbe_expander/transcriber.rs
+++ b/crates/mbe/src/mbe_expander/transcriber.rs
@@ -6,8 +6,8 @@ use syntax::SmolStr;
6use super::ExpandResult; 6use super::ExpandResult;
7use crate::{ 7use crate::{
8 mbe_expander::{Binding, Bindings, Fragment}, 8 mbe_expander::{Binding, Bindings, Fragment},
9 parser::{parse_template, Op, RepeatKind, Separator}, 9 parser::{Op, RepeatKind, Separator},
10 ExpandError, 10 ExpandError, MetaTemplate,
11}; 11};
12 12
13impl Bindings { 13impl Bindings {
@@ -50,7 +50,10 @@ impl Bindings {
50 } 50 }
51} 51}
52 52
53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { 53pub(super) fn transcribe(
54 template: &MetaTemplate,
55 bindings: &Bindings,
56) -> ExpandResult<tt::Subtree> {
54 assert!(template.delimiter == None); 57 assert!(template.delimiter == None);
55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; 58 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
56 let mut arena: Vec<tt::TokenTree> = Vec::new(); 59 let mut arena: Vec<tt::TokenTree> = Vec::new();
@@ -76,35 +79,35 @@ struct ExpandCtx<'a> {
76 79
77fn expand_subtree( 80fn expand_subtree(
78 ctx: &mut ExpandCtx, 81 ctx: &mut ExpandCtx,
79 template: &tt::Subtree, 82 template: &MetaTemplate,
80 arena: &mut Vec<tt::TokenTree>, 83 arena: &mut Vec<tt::TokenTree>,
81) -> ExpandResult<tt::Subtree> { 84) -> ExpandResult<tt::Subtree> {
82 // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation 85 // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
83 let start_elements = arena.len(); 86 let start_elements = arena.len();
84 let mut err = None; 87 let mut err = None;
85 for op in parse_template(template) { 88 for op in template.iter() {
86 let op = match op { 89 let op = match op {
87 Ok(op) => op, 90 Ok(op) => op,
88 Err(e) => { 91 Err(e) => {
89 err = Some(e); 92 err = Some(e.clone());
90 break; 93 break;
91 } 94 }
92 }; 95 };
93 match op { 96 match op {
94 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()), 97 Op::Leaf(tt) => arena.push(tt.clone().into()),
95 Op::TokenTree(tt::TokenTree::Subtree(tt)) => { 98 Op::Subtree(tt) => {
96 let ExpandResult { value: tt, err: e } = expand_subtree(ctx, tt, arena); 99 let ExpandResult { value: tt, err: e } = expand_subtree(ctx, &tt, arena);
97 err = err.or(e); 100 err = err.or(e);
98 arena.push(tt.into()); 101 arena.push(tt.into());
99 } 102 }
100 Op::Var { name, .. } => { 103 Op::Var { name, .. } => {
101 let ExpandResult { value: fragment, err: e } = expand_var(ctx, name); 104 let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name);
102 err = err.or(e); 105 err = err.or(e);
103 push_fragment(arena, fragment); 106 push_fragment(arena, fragment);
104 } 107 }
105 Op::Repeat { subtree, kind, separator } => { 108 Op::Repeat { subtree, kind, separator } => {
106 let ExpandResult { value: fragment, err: e } = 109 let ExpandResult { value: fragment, err: e } =
107 expand_repeat(ctx, subtree, kind, separator, arena); 110 expand_repeat(ctx, subtree, *kind, separator, arena);
108 err = err.or(e); 111 err = err.or(e);
109 push_fragment(arena, fragment) 112 push_fragment(arena, fragment)
110 } 113 }
@@ -161,9 +164,9 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
161 164
162fn expand_repeat( 165fn expand_repeat(
163 ctx: &mut ExpandCtx, 166 ctx: &mut ExpandCtx,
164 template: &tt::Subtree, 167 template: &MetaTemplate,
165 kind: RepeatKind, 168 kind: RepeatKind,
166 separator: Option<Separator>, 169 separator: &Option<Separator>,
167 arena: &mut Vec<tt::TokenTree>, 170 arena: &mut Vec<tt::TokenTree>,
168) -> ExpandResult<Fragment> { 171) -> ExpandResult<Fragment> {
169 let mut buf: Vec<tt::TokenTree> = Vec::new(); 172 let mut buf: Vec<tt::TokenTree> = Vec::new();
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}