Reputation: 2092
I'm working on a lexer in Rust.
Desired API:
enum Token<'input> {
Name(&'input str)
}
let mut lexicon = LexiconBuilder::<Token>::new()
.token("[a-zA-Z]+", |s| Token::Name(s))
// among others
.build();
let mut lexer = Lexer::new(lexicon, "input");
The idea is the user can provide a regular expression, along with a closure that gets run when the regex matches the input text. However, I'm having trouble proving to the lifetime checker that the slice that gets passed into token()
's closure lives long enough. From my POV, it seems safe, as the tokens aren't returned until you provide a string.
I've spent quite awhile trying to thread input lifetime through all of the types, however I can't ever seem to prove that the lexicon's (ergo, the rule's handler) lifetime will match/dominate the input's.
Upvotes: 1
Views: 197
Reputation: 29193
type Handler<T> = fn(&str) -> T;
Is not a complete type. The &str
needs to have a lifetime on it, but one is not specified. Lifetime elision means that this expands to
type Handler<T> = for<'a> fn(&'a str) -> T;
So Handler
s don't know the lifetime of the &str
s being given to them. For some 'input
, to construct a Rule<Token<'input>>
, you need a Handler<Token<'input>>
, but that means you need for<'a> fn(&'a str) -> Token<'input>
, where the Token
wants a &'input str
but you only have a &'a str
. You need to make 'input
a parameter of Handler
, so it can restrict the arguments it will accept:
type Handler<'input, T> = fn(&'input str) -> T;
And this must propagate through all your other types. Playground link.
The code in your question is incomplete, and the code in the playground doesn't match it. If you've already tried this, then you're going to have to tell us what went wrong more clearly.
Upvotes: 5