codehelion_frontend_rust/
lib.rs1pub mod ir;
10mod lexer;
11mod units;
12
13use codehelion_core::discovery::Language;
14use codehelion_core::frontend::{Frontend, LexedFile};
15
16pub const FRONTEND_VERSION: &str = "rust-lexer-v1";
24
25#[derive(Debug, Clone, Copy, Default)]
27pub struct RustFrontend;
28
29impl Frontend for RustFrontend {
30 fn language(&self) -> Language {
31 Language::Rust
32 }
33
34 fn frontend_version(&self) -> &'static str {
35 FRONTEND_VERSION
36 }
37
38 fn lex(&self, source: &str) -> LexedFile {
39 let (tokens, diagnostics) = lexer::lex(source);
40 let units = units::detect(&tokens);
41 LexedFile {
42 language: Language::Rust,
43 frontend_version: FRONTEND_VERSION,
44 tokens,
45 units,
46 diagnostics,
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use codehelion_core::ir::StructuralFrontend;
55 use proptest::prelude::*;
56 use std::time::{Duration, Instant};
57
58 #[test]
59 fn frontend_reports_language_and_version() {
60 let frontend = RustFrontend;
61 assert_eq!(frontend.language(), Language::Rust);
62 assert_eq!(frontend.frontend_version(), FRONTEND_VERSION);
63 }
64
65 #[test]
66 fn lexing_a_file_yields_tokens_units_and_the_version() {
67 let lexed = RustFrontend.lex("fn main() { let x = 1; }");
68 assert_eq!(lexed.language, Language::Rust);
69 assert_eq!(lexed.frontend_version, FRONTEND_VERSION);
70 assert!(!lexed.tokens.is_empty());
71 assert_eq!(lexed.units.len(), 1);
72 assert!(lexed.diagnostics.is_empty());
73 }
74
75 proptest! {
76 #![proptest_config(ProptestConfig::with_cases(64))]
77
78 #[test]
79 fn arbitrary_text_never_panics(source in proptest::collection::vec(any::<char>(), 0..1024)
80 .prop_map(|characters| characters.into_iter().collect::<String>())) {
81 let started = Instant::now();
82 let _ = RustFrontend.lex(&source);
83 let _ = ir::RustStructuralFrontend.parse(&source);
84 prop_assert!(
85 started.elapsed() < Duration::from_secs(1),
86 "a bounded frontend input took too long"
87 );
88 }
89 }
90}