1use std::error::Error;
2use std::path::Path;
3
4use llmcc_core::*;
5
6pub struct LlmccOptions {
8 pub files: Vec<String>,
9 pub dir: Option<String>,
10 pub print_ir: bool,
11 pub print_block: bool,
12 pub project_graph: bool,
13 pub pagerank: bool,
14 pub top_k: Option<usize>,
15 pub pagerank_direction: String,
16 pub pagerank_iterations: usize,
17 pub query: Option<String>,
18 pub recursive: bool,
19 pub dependents: bool,
20}
21
22pub fn run_main<L: LanguageTrait>(opts: &LlmccOptions) -> Result<Option<String>, Box<dyn Error>> {
23 let (cc, files) = if let Some(dir) = opts.dir.as_ref() {
24 let ctx = CompileCtxt::from_dir::<_, L>(Path::new(dir))?;
25 let file_paths = ctx.get_files();
26 (ctx, file_paths)
27 } else {
28 let ctx = CompileCtxt::from_files::<L>(&opts.files)?;
29 (ctx, opts.files.clone())
30 };
31
32 let use_compact_builder = opts.project_graph && opts.query.is_none();
33 build_llmcc_ir_with_config::<L>(&cc, IrBuildConfig::default())?;
34 let globals = cc.create_globals();
35
36 if opts.print_ir {
37 for (index, _) in files.iter().enumerate() {
38 let unit = cc.compile_unit(index);
39 print_llmcc_ir(unit);
40 }
41 }
42
43 for (index, _) in files.iter().enumerate() {
44 let unit = cc.compile_unit(index);
45 L::collect_symbols(unit, globals);
46 }
47
48 let mut pg = ProjectGraph::new(&cc);
49 let graph_config = if use_compact_builder {
51 GraphBuildConfig::compact()
52 } else {
53 GraphBuildConfig::default()
54 };
55 for (index, _) in files.iter().enumerate() {
56 let unit = cc.compile_unit(index);
57 L::bind_symbols(unit, globals);
58 let unit_graph = build_llmcc_graph_with_config::<L>(unit, index, graph_config)?;
59
60 if opts.print_block {
61 print_llmcc_graph(unit_graph.root(), unit);
62 }
63
64 pg.add_child(unit_graph);
65 }
66
67 pg.link_units();
68
69 if opts.recursive && opts.dependents {
70 return Err("`--recursive` is not supported together with `--dependents`".into());
71 }
72
73 let mut outputs = Vec::new();
74
75 if opts.project_graph {
76 if opts.pagerank {
77 let limit = Some(opts.top_k.unwrap_or(25));
78 pg.set_compact_rank_limit(limit);
79
80 let direction = match opts.pagerank_direction.as_str() {
82 "depends-on" => llmcc_core::PageRankDirection::DependsOn,
83 _ => llmcc_core::PageRankDirection::DependedBy, };
85 pg.set_pagerank_direction(direction);
86 }
87 outputs.push(pg.render_compact_graph());
88 } else {
89 if let Some(name) = opts.query.as_ref() {
90 let query = ProjectQuery::new(&pg);
91 let query_output = if opts.dependents {
92 query.find_depended(name).format_for_llm()
93 } else if opts.recursive {
94 query.find_depends_recursive(name).format_for_llm()
95 } else {
96 query.find_depends(name).format_for_llm()
97 };
98 outputs.push(query_output);
99 }
100 }
101
102 if outputs.is_empty() {
103 Ok(None)
104 } else {
105 Ok(Some(outputs.join("\n")))
106 }
107}