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?)
There are some crates which do something like this (e.g.
string_cache_codegen):(@nnethercote came across this when profiling
html5ever's compilation)Also, prefixing patterns with
@footo 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:
Whereas for something using
@foorules it could be:(where
DecisionTree::Doneindicates the arms to continue with)cc @rust-lang/compiler (this might need a design meeting?)