typestar

tokenizer.rs en Rust

Un tokenizador de copia cero: cada token es un slice del código fuente original.

#[derive(Debug, PartialEq)]
enum Token<'a> {
    Word(&'a str),
    Number(&'a str),
    Symbol(char),
}

struct Lexer<'a> {
    source: &'a str,
    pos: usize,
}

impl<'a> Lexer<'a> {
    fn new(source: &'a str) -> Self {
        Lexer { source, pos: 0 }
    }

    fn rest(&self) -> &'a str {
        &self.source[self.pos..]
    }

    fn take_while<F: Fn(char) -> bool>(&mut self, test: F) -> &'a str {
        let start = self.pos;
        for c in self.rest().chars() {
            if !test(c) {
                break;
            }
            self.pos += c.len_utf8();
        }
        &self.source[start..self.pos]
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Token<'a>> {
        self.take_while(char::is_whitespace);
        let c = self.rest().chars().next()?;

        if c.is_ascii_digit() {
            return Some(Token::Number(
                self.take_while(|c| c.is_ascii_digit()),
            ));
        }
        if c.is_alphabetic() || c == '_' {
            return Some(Token::Word(
                self.take_while(|c| c.is_alphanumeric() || c == '_'),
            ));
        }
        self.pos += c.len_utf8();
        Some(Token::Symbol(c))
    }
}

fn main() {
    let source = "let total = count * 42;";
    let tokens: Vec<Token> = Lexer::new(source).collect();

    for token in &tokens {
        println!("{:?}", token);
    }

    let words = tokens
        .iter()
        .filter(|t| matches!(t, Token::Word(_)))
        .count();
    println!("{words} words, {} tokens", tokens.len());
    assert_eq!(tokens[0], Token::Word("let"));
}

Cómo funciona

  1. El enum Token presta de la entrada, así que nada se copia.
  2. El lexer camina bytes y corta en las fronteras que encuentra.
  3. El lifetime del struct ata cada token a esa fuente.

Palabras clave y builtins usados aquí

El intento, en números

Líneas
70
Caracteres a escribir
1272
Tokens
462
Ritmo de tres estrellas
115 tpm

Al ritmo de tres estrellas de 115 tokens por minuto, este intento toma unos 241 segundos.

Escribe este fragmento

Paso 1 de 1 en Bis; paso 11 de 11 en Lifetimes y mutabilidad interior.

← Anterior