use std::collections::BTreeMap;
use std::fmt::Write as _;
use meta_language::{LinkNetwork, LinkType, NetworkProjection, ParseConfiguration};
const RUST_GRAMMAR_LABEL: &str = "rust";
pub const TARGET_MODULE_PATH: &str = "src/agentic_coding/planner.rs";
const TARGET_MODULE_SOURCE: &str = include_str!("planner.rs");
pub const AST_PATH: &str = "self-ast.lino";
pub const AST_TASK: &str =
"Store the CST/AST of our Rust meta algorithm in our data so the system \
can reason about itself: parse the planner module and record its \
abstract-syntax node census in Links Notation.";
const AST_KEYWORDS: [&str; 4] = [
"cst/ast",
"cst / ast",
"abstract-syntax",
"reason about itself",
];
#[must_use]
pub fn is_self_ast_task(prompt: &str) -> bool {
let lower = prompt.to_lowercase();
let names_ast = AST_KEYWORDS.iter().any(|keyword| lower.contains(keyword))
|| (lower.contains("ast") && lower.contains("meta algorithm"));
let self_reference = lower.contains("our")
|| lower.contains("itself")
|| lower.contains("meta algorithm")
|| lower.contains("planner");
names_ast && self_reference
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AstNodeCount {
pub kind: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AstCensus {
pub total_link_count: usize,
pub named_node_count: usize,
pub text_preserved: bool,
pub clean: bool,
pub node_kinds: Vec<AstNodeCount>,
}
#[must_use]
pub fn ast_census(source: &str) -> AstCensus {
let network = LinkNetwork::parse(source, RUST_GRAMMAR_LABEL, ParseConfiguration::default());
let mut histogram: BTreeMap<String, usize> = BTreeMap::new();
for link in network.projected_links(NetworkProjection::AbstractSyntax) {
let metadata = link.metadata();
if metadata.link_type() != Some(LinkType::Syntax) || !metadata.is_named() {
continue;
}
if let Some(kind) = metadata.term() {
*histogram.entry(kind.to_owned()).or_insert(0) += 1;
}
}
let named_node_count = histogram.values().sum();
let node_kinds = histogram
.into_iter()
.map(|(kind, count)| AstNodeCount { kind, count })
.collect();
AstCensus {
total_link_count: network.len(),
named_node_count,
text_preserved: network.reconstruct_text() == source,
clean: network.verify_full_match(None).is_clean(),
node_kinds,
}
}
#[must_use]
pub fn render_ast_document(target_path: &str, source: &str) -> String {
let census = ast_census(source);
let mut out = String::new();
let _ = writeln!(out, "self_ast");
let _ = writeln!(out, " target {target_path}");
let _ = writeln!(out, " language rust");
let _ = writeln!(out, " engine meta_language");
let _ = writeln!(out, " component meta-language");
let _ = writeln!(out, " grammar_label {RUST_GRAMMAR_LABEL}");
let _ = writeln!(out, " projection abstract_syntax");
let _ = writeln!(out, " text_preserved {}", census.text_preserved);
let _ = writeln!(out, " clean {}", census.clean);
let _ = writeln!(out, " total_link_count {}", census.total_link_count);
let _ = writeln!(out, " named_node_count {}", census.named_node_count);
let _ = writeln!(out, " distinct_node_kinds {}", census.node_kinds.len());
let _ = writeln!(out, " node_kinds");
for AstNodeCount { kind, count } in &census.node_kinds {
let _ = writeln!(out, " {kind} {count}");
}
format!("{}\n", out.trim_end())
}
#[must_use]
pub fn render_document() -> String {
render_ast_document(TARGET_MODULE_PATH, TARGET_MODULE_SOURCE)
}
#[must_use]
pub fn target_census() -> AstCensus {
ast_census(TARGET_MODULE_SOURCE)
}
#[must_use]
pub fn final_answer(document: &str) -> String {
format!(
"Stored the CST/AST of our Rust meta algorithm ({TARGET_MODULE_PATH}) in our data, parsed \
through the meta-language links network (the sole CST/AST engine here) and recorded as an \
abstract-syntax node census — a real step toward the system reasoning about itself.\n\n\
Generated document ({AST_PATH}):\n\n{document}",
document = document.trim_end(),
)
}