pub mod ir;
mod lexer;
mod units;
use codehelion_core::discovery::Language;
use codehelion_core::frontend::{Frontend, LexedFile};
pub const FRONTEND_VERSION: &str = "rust-lexer-v1";
#[derive(Debug, Clone, Copy, Default)]
pub struct RustFrontend;
impl Frontend for RustFrontend {
fn language(&self) -> Language {
Language::Rust
}
fn frontend_version(&self) -> &'static str {
FRONTEND_VERSION
}
fn lex(&self, source: &str) -> LexedFile {
let (tokens, diagnostics) = lexer::lex(source);
let units = units::detect(&tokens);
LexedFile {
language: Language::Rust,
frontend_version: FRONTEND_VERSION,
tokens,
units,
diagnostics,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use codehelion_core::ir::StructuralFrontend;
use proptest::prelude::*;
use std::time::{Duration, Instant};
#[test]
fn frontend_reports_language_and_version() {
let frontend = RustFrontend;
assert_eq!(frontend.language(), Language::Rust);
assert_eq!(frontend.frontend_version(), FRONTEND_VERSION);
}
#[test]
fn lexing_a_file_yields_tokens_units_and_the_version() {
let lexed = RustFrontend.lex("fn main() { let x = 1; }");
assert_eq!(lexed.language, Language::Rust);
assert_eq!(lexed.frontend_version, FRONTEND_VERSION);
assert!(!lexed.tokens.is_empty());
assert_eq!(lexed.units.len(), 1);
assert!(lexed.diagnostics.is_empty());
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(64))]
#[test]
fn arbitrary_text_never_panics(source in proptest::collection::vec(any::<char>(), 0..1024)
.prop_map(|characters| characters.into_iter().collect::<String>())) {
let started = Instant::now();
let _ = RustFrontend.lex(&source);
let _ = ir::RustStructuralFrontend.parse(&source);
prop_assert!(
started.elapsed() < Duration::from_secs(1),
"a bounded frontend input took too long"
);
}
}
}