agentic_codebase/engine/
compile.rs1use std::path::{Path, PathBuf};
8use std::time::Instant;
9
10use crate::format::AcbWriter;
11use crate::graph::CodeGraph;
12use crate::parse::parser::{ParseOptions, Parser};
13use crate::semantic::analyzer::{AnalyzeOptions, SemanticAnalyzer};
14use crate::types::{AcbResult, Language};
15
16#[derive(Debug, Clone)]
18pub struct CompileOptions {
19 pub output: PathBuf,
21 pub languages: Vec<Language>,
23 pub exclude_patterns: Vec<String>,
25 pub include_tests: bool,
27 pub detect_patterns: bool,
29 pub extract_concepts: bool,
31 pub trace_ffi: bool,
33}
34
35impl Default for CompileOptions {
36 fn default() -> Self {
37 Self {
38 output: PathBuf::from("graph.acb"),
39 languages: Vec::new(),
40 exclude_patterns: Vec::new(),
41 include_tests: true,
42 detect_patterns: true,
43 extract_concepts: true,
44 trace_ffi: true,
45 }
46 }
47}
48
49pub struct CompileResult {
51 pub graph: CodeGraph,
53 pub stats: CompileStats,
55}
56
57#[derive(Debug, Clone)]
59pub struct CompileStats {
60 pub files_parsed: usize,
62 pub parse_errors: usize,
64 pub units_created: usize,
66 pub edges_created: usize,
68 pub languages: Vec<Language>,
70 pub duration: std::time::Duration,
72}
73
74pub struct CompilePipeline;
76
77impl CompilePipeline {
78 pub fn new() -> Self {
80 Self
81 }
82
83 pub fn compile(&self, dir: &Path, opts: &CompileOptions) -> AcbResult<CompileResult> {
88 let start = Instant::now();
89
90 let parse_opts = ParseOptions {
92 languages: opts.languages.clone(),
93 exclude: opts.exclude_patterns.clone(),
94 include_tests: opts.include_tests,
95 ..ParseOptions::default()
96 };
97
98 tracing::info!("Parsing {}", dir.display());
99 let parser = Parser::new();
100 let parse_result = parser.parse_directory(dir, &parse_opts)?;
101
102 let files_parsed = parse_result.stats.files_parsed;
103 let parse_errors = parse_result.errors.len();
104
105 if !parse_result.errors.is_empty() {
106 for err in &parse_result.errors {
107 tracing::warn!("Parse error: {}: {}", err.path.display(), err.message);
108 }
109 }
110
111 let analyze_opts = AnalyzeOptions {
113 detect_patterns: opts.detect_patterns,
114 extract_concepts: opts.extract_concepts,
115 trace_ffi: opts.trace_ffi,
116 };
117
118 tracing::info!("Analyzing {} units", parse_result.units.len());
119 let analyzer = SemanticAnalyzer::new();
120 let graph = analyzer.analyze(parse_result.units, &analyze_opts)?;
121
122 let duration = start.elapsed();
123
124 let stats = CompileStats {
125 files_parsed,
126 parse_errors,
127 units_created: graph.unit_count(),
128 edges_created: graph.edge_count(),
129 languages: graph.languages().iter().copied().collect(),
130 duration,
131 };
132
133 tracing::info!(
134 "Compiled {} units, {} edges in {:.2?}",
135 stats.units_created,
136 stats.edges_created,
137 stats.duration
138 );
139
140 Ok(CompileResult { graph, stats })
141 }
142
143 pub fn write(&self, graph: &CodeGraph, output: &Path) -> AcbResult<()> {
145 tracing::info!("Writing {}", output.display());
146
147 if let Some(parent) = output.parent() {
148 std::fs::create_dir_all(parent)?;
149 }
150
151 let writer = AcbWriter::new(graph.dimension());
152 writer.write_to_file(graph, output)?;
153
154 tracing::info!("Wrote {}", output.display());
155 Ok(())
156 }
157
158 pub fn compile_and_write(&self, dir: &Path, opts: &CompileOptions) -> AcbResult<CompileResult> {
160 let result = self.compile(dir, opts)?;
161 self.write(&result.graph, &opts.output)?;
162 Ok(result)
163 }
164}
165
166impl Default for CompilePipeline {
167 fn default() -> Self {
168 Self::new()
169 }
170}