To follow DRY principles I'm trying to reuse boilerplate as a function call in Rust:
use logos::Logos;
use std::fmt;
use std::ops::Range;
#[derive(Logos, Debug, PartialEq, Copy, Clone)]
pub enum Token<'a> {
#[regex("[ \r\n\t]+", logos::skip)]
#[error]
Error,
}
// use Logos lexer in Lalrpop, from: https://github.com/ratmice/json-pop/blob/master/src/lex.rs#L54
impl<'input> TheToken<'input> {
pub fn to_lalr_triple((t, r): (TheToken<'input>, Range<usize>)) -> Result<(usize, TheToken, usize), CompilationError> {
if t == TheToken::Error {
Err(CompilationError::LexicalError { range: r })
} else {
Ok((r.start, t, r.end))
}
}
}
#[derive(Debug)]
pub enum CompilationError {
LexicalError { range: Range<usize> },
NumericalError { range: Range<usize> },
UnterminatedStringLiteral { range: Range<usize> },
}
// here is the failure:
fn to_lexer<'input>(bytes: &str) -> Box<dyn Iterator<Item=TheToken<'input>>> {
TheToken::lexer(bytes).spanned().map(TheToken::to_lalr_triple)
}
and from what I gather, map should return as an iter based on:
However, I am using spanned first, and that changes the return type dramatically. If I paste in what the compiler says it's expecting, there are loads of syntax errors. So how can I indicate the return type properly?:
error[E0308]: mismatched types
--> src/parser/lex.rs:110:3
|
109 | fn lexed<'input>(bytes: &str) -> Box<dyn Iterator<Item=TheToken<'input>>> {
| ---------------------------------------- expectedBox<(dyn std::iter::Iterator<Item = TheToken<'input>> + 'static)>because of return type
110 | TheToken::lexer(bytes).spanned().map(TheToken::to_lalr_triple)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected structBox, found structstd::iter::Map
|
= note: expected structBox<(dyn std::iter::Iterator<Item = TheToken<'input>> + 'static)>
found structstd::iter::Map<SpannedIter<'_, TheToken<'_>>, fn((TheToken<'_>, std::ops::Range<usize>)) -> Result<(usize, TheToken<'_>, usize), CompilationError> {TheToken::<'_>::to_lalr_triple}>