Skip to content

Commit 9d8af91

Browse files
committed
NFA parser for mbe matcher
1 parent f682627 commit 9d8af91

File tree

9 files changed

+580
-163
lines changed

9 files changed

+580
-163
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/mbe/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ syntax = { path = "../syntax", version = "0.0.0" }
1818
parser = { path = "../parser", version = "0.0.0" }
1919
tt = { path = "../tt", version = "0.0.0" }
2020
test_utils = { path = "../test_utils", version = "0.0.0" }
21+
stdx = { path = "../stdx" }
2122

2223
[dev-dependencies]
2324
profile = { path = "../profile", version = "0.0.0" }

crates/mbe/src/benchmark.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,12 @@ fn benchmark_expand_macro_rules() {
4040
.into_iter()
4141
.map(|(id, tt)| {
4242
let res = rules[&id].expand(&tt);
43-
if res.err.is_some() {
44-
// FIXME:
45-
// Currently `invocation_fixtures` will generate some correct invocations but
46-
// cannot be expanded by mbe. We ignore errors here.
47-
// See: https://github.com/rust-analyzer/rust-analyzer/issues/4777
48-
eprintln!("err from {} {:?}", id, res.err);
49-
}
43+
assert!(res.err.is_none());
5044
res.value.token_trees.len()
5145
})
5246
.sum()
5347
};
54-
assert_eq!(hash, 66995);
48+
assert_eq!(hash, 69413);
5549
}
5650

5751
fn macro_rules_fixtures() -> FxHashMap<String, MacroRules> {
@@ -77,7 +71,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree> {
7771
.collect()
7872
}
7973

80-
// Generate random invocation fixtures from rules
74+
/// Generate random invocation fixtures from rules
8175
fn invocation_fixtures(rules: &FxHashMap<String, MacroRules>) -> Vec<(String, tt::Subtree)> {
8276
let mut seed = 123456789;
8377
let mut res = Vec::new();
@@ -86,11 +80,31 @@ fn invocation_fixtures(rules: &FxHashMap<String, MacroRules>) -> Vec<(String, tt
8680
for rule in &it.rules {
8781
// Generate twice
8882
for _ in 0..2 {
89-
let mut subtree = tt::Subtree::default();
90-
for op in rule.lhs.iter() {
91-
collect_from_op(op, &mut subtree, &mut seed);
83+
// The input are generated by filling the `Op` randomly.
84+
// However, there are some cases generated are ambiguous for expanding, for example:
85+
// ```rust
86+
// macro_rules! m {
87+
// ($($t:ident),* as $ty:ident) => {}
88+
// }
89+
// m!(as u32); // error: local ambiguity: multiple parsing options: built-in NTs ident ('t') or 1 other option.
90+
// ```
91+
//
92+
// So we just skip any error cases and try again
93+
let mut try_cnt = 0;
94+
loop {
95+
let mut subtree = tt::Subtree::default();
96+
for op in rule.lhs.iter() {
97+
collect_from_op(op, &mut subtree, &mut seed);
98+
}
99+
if it.expand(&subtree).err.is_none() {
100+
res.push((name.clone(), subtree));
101+
break;
102+
}
103+
try_cnt += 1;
104+
if try_cnt > 100 {
105+
panic!("invocaton fixture {} cannot be generated.\n", name);
106+
}
92107
}
93-
res.push((name.clone(), subtree));
94108
}
95109
}
96110
}

crates/mbe/src/expander.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
mod matcher;
66
mod transcriber;
77

8-
use rustc_hash::FxHashMap;
8+
use smallvec::SmallVec;
99
use syntax::SmolStr;
1010

1111
use crate::{ExpandError, ExpandResult};
@@ -28,10 +28,10 @@ pub(crate) fn expand_rules(
2828
return ExpandResult::ok(value);
2929
}
3030
}
31-
// Use the rule if we matched more tokens, or had fewer errors
31+
// Use the rule if we matched more tokens, or bound variables count
3232
if let Some((prev_match, _)) = &match_ {
33-
if (new_match.unmatched_tts, new_match.err_count)
34-
< (prev_match.unmatched_tts, prev_match.err_count)
33+
if (new_match.unmatched_tts, -(new_match.bound_count as i32))
34+
< (prev_match.unmatched_tts, -(prev_match.bound_count as i32))
3535
{
3636
match_ = Some((new_match, rule));
3737
}
@@ -94,19 +94,19 @@ pub(crate) fn expand_rules(
9494
/// In other words, `Bindings` is a *multi* mapping from `SmolStr` to
9595
/// `tt::TokenTree`, where the index to select a particular `TokenTree` among
9696
/// many is not a plain `usize`, but an `&[usize]`.
97-
#[derive(Debug, Default)]
97+
#[derive(Debug, Default, Clone, PartialEq, Eq)]
9898
struct Bindings {
99-
inner: FxHashMap<SmolStr, Binding>,
99+
inner: SmallVec<[(SmolStr, Binding); 4]>,
100100
}
101101

102-
#[derive(Debug)]
102+
#[derive(Debug, Clone, PartialEq, Eq)]
103103
enum Binding {
104104
Fragment(Fragment),
105105
Nested(Vec<Binding>),
106106
Empty,
107107
}
108108

109-
#[derive(Debug, Clone)]
109+
#[derive(Debug, Clone, PartialEq, Eq)]
110110
enum Fragment {
111111
/// token fragments are just copy-pasted into the output
112112
Tokens(tt::TokenTree),

0 commit comments

Comments
 (0)