use pedant_syntax::go::GoFactLimits;
use pedant_syntax::tree_sitter::parse_bound;
use pedant_syntax::{StructureInventoryLimits, StructureRecord, StructureSpan, SyntaxLanguage};
use crate::observe::{self, Observation};
use super::condition::{self, GoBuildCondition};
use super::facts::GoSourceFacts;
use super::fault::GoSourceFault;
use super::paths;
use super::snapshot_error::GoSourceDefect;
#[derive(Debug)]
pub struct GoFileInventory {
facts: GoSourceFacts,
conditions: Box<[GoBuildCondition]>,
structures: Box<[StructureRecord]>,
fact_count: u32,
syntax_depth: u32,
}
impl GoFileInventory {
pub fn of_source(path: &str, text: &str, limits: GoFactLimits) -> Result<Self, GoSourceFault> {
let Some(parsed) = parse_bound(text, SyntaxLanguage::Go) else {
return Err(GoSourceFault::Incomplete(GoSourceDefect::Unparsed));
};
observe::record(Observation::SourceParse(path));
if parsed.has_errors() {
return Err(GoSourceFault::Incomplete(GoSourceDefect::Recovered));
}
let facts = parsed
.go_file_facts(limits)
.map_err(GoSourceFault::FactExtraction)?;
observe::record(Observation::SiteVisit(path));
if facts.package_name().is_none() {
return Err(GoSourceFault::MissingPackageClause);
}
let structures = facts
.structure_inventory(structure_limits(limits)?)
.map_err(|error| GoSourceFault::StructureProjection {
reason: error.to_string().into_boxed_str(),
})?
.retained();
Ok(Self {
conditions: condition::conditions_of(paths::file_name(path), &facts),
structures,
fact_count: facts.fact_count(),
syntax_depth: facts.syntax_depth(),
facts: GoSourceFacts::of(&facts),
})
}
pub fn facts(&self) -> &GoSourceFacts {
&self.facts
}
pub fn conditions(&self) -> &[GoBuildCondition] {
&self.conditions
}
pub fn structures(&self) -> &[StructureRecord] {
&self.structures
}
pub fn definition_span(&self, position: usize) -> Option<StructureSpan> {
self.structures.get(position).map(StructureRecord::span)
}
pub fn fact_count(&self) -> u32 {
self.fact_count
}
pub fn syntax_depth(&self) -> u32 {
self.syntax_depth
}
}
fn structure_limits(limits: GoFactLimits) -> Result<StructureInventoryLimits, GoSourceFault> {
StructureInventoryLimits::new(limits.max_syntax_depth(), limits.max_facts()).ok_or_else(|| {
GoSourceFault::StructureProjection {
reason: format!(
"a ceiling of zero admits no structure: syntax depth {}, facts {}",
limits.max_syntax_depth(),
limits.max_facts()
)
.into_boxed_str(),
}
})
}