codehelion_frontend_c/
lib.rs1pub mod dialect;
16pub mod ir;
17pub mod lexer;
18pub mod units;
19
20use codehelion_core::discovery::Language;
21use codehelion_core::frontend::{Frontend, LexedFile};
22
23pub const C_FAMILY_LEXER_VERSION: &str = "c-family-lexer-v1";
28
29pub const FRONTEND_VERSION: &str = "c-lexer-v1+c-family-lexer-v1";
32
33#[derive(Debug, Clone, Copy, Default)]
35pub struct CFrontend;
36
37impl Frontend for CFrontend {
38 fn language(&self) -> Language {
39 Language::C
40 }
41
42 fn frontend_version(&self) -> &'static str {
43 FRONTEND_VERSION
44 }
45
46 fn lex(&self, source: &str) -> LexedFile {
47 let (tokens, mut diagnostics) = lexer::lex(source, &dialect::C);
48 let (units, unit_diagnostics) = units::detect(&tokens, &dialect::C);
49 diagnostics.extend(unit_diagnostics);
50 LexedFile {
51 language: Language::C,
52 frontend_version: FRONTEND_VERSION,
53 tokens,
54 units,
55 diagnostics,
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use codehelion_core::ir::StructuralFrontend;
64 use proptest::prelude::*;
65 use std::time::{Duration, Instant};
66
67 #[test]
68 fn frontend_reports_language_and_version() {
69 let frontend = CFrontend;
70 assert_eq!(frontend.language(), Language::C);
71 assert_eq!(frontend.frontend_version(), FRONTEND_VERSION);
72 assert!(FRONTEND_VERSION.ends_with(C_FAMILY_LEXER_VERSION));
73 }
74
75 #[test]
76 fn lexing_a_file_yields_tokens_units_and_the_version() {
77 let lexed = CFrontend.lex("int main(void) { return 0; }");
78 assert_eq!(lexed.language, Language::C);
79 assert_eq!(lexed.frontend_version, FRONTEND_VERSION);
80 assert!(!lexed.tokens.is_empty());
81 assert_eq!(lexed.units.len(), 1);
82 assert!(lexed.diagnostics.is_empty());
83 }
84
85 proptest! {
86 #![proptest_config(ProptestConfig::with_cases(64))]
87
88 #[test]
89 fn arbitrary_text_never_panics(source in proptest::collection::vec(any::<char>(), 0..1024)
90 .prop_map(|characters| characters.into_iter().collect::<String>())) {
91 let started = Instant::now();
92 let _ = CFrontend.lex(&source);
93 let _ = ir::CStructuralFrontend.parse(&source);
94 prop_assert!(
95 started.elapsed() < Duration::from_secs(1),
96 "a bounded frontend input took too long"
97 );
98 }
99 }
100}