Description
There are some crates which do something like this (e.g. string_cache_codegen
):
macro_rules! foo {
("a") => (A);
("b") => (B);
("c") => (C);
// ... etc. (maybe hundreds more)
}
(@nnethercote came across this when profiling html5ever
's compilation)
Also, prefixing patterns with @foo
to create "internal rules" is common.
But the current implementation (AFAICT) has to check each of the patterns in turn.
Instead, we could build something like a decision tree ahead of time, from the constant (i.e. $
-less) prefix of all arms, using maps for operators/idents/literals, to make the pattern-matching of the prefix amortize to being linear in the number of input tokens.
We could keep it simple by limiting the constant prefix to leaf tokens (no (...)
, [...]
or {...}
).
For the example above, we'd pre-compute something like this:
DecisionTree::Match {
op: {},
ident: {},
literal: {
"a": DecisionTree::Done([0]),
"b": DecisionTree::Done([1]),
"c": DecisionTree::Done([2]),
// ...
},
}
Whereas for something using @foo
rules it could be:
DecisionTree::Match {
op: {
'@': DecisionTree::Match {
op: {},
ident: {
"foo": DecisionTree::Done([0, 1]),
"bar": DecisionTree::Done([2, 3, 4]),
"baz": DecisionTree::Done([5]),
},
literal: {},
}
},
ident: {},
literal: {},
}
(where DecisionTree::Done
indicates the arms to continue with)
cc @rust-lang/compiler (this might need a design meeting?)