///|
/// A parsed and semantically indexed RTL source unit.
pub struct Analysis {
  file : @source.SourceFile
  parsed : @parser.ParseResult
  semantic_index : @semantic.SemanticIndex
}

///|
/// Analyze named source text while preserving its file identity for diagnostics.
pub fn analyze_file(file_name : String, text : String) -> Analysis {
  let file = @source.SourceFile::new(file_name, text)
  let parsed = @parser.parse(file)
  let semantic_index = @semantic.index(parsed.design)
  { file, parsed, semantic_index }
}

///|
/// Analyze an in-memory RTL document.
pub fn analyze_text(text : String) -> Analysis {
  analyze_file("", text)
}

///|
/// Return the source file associated with this analysis.
pub fn Analysis::file(self : Analysis) -> @source.SourceFile {
  self.file
}

///|
/// Return parser output, including recovery diagnostics and metrics.
pub fn Analysis::parse(self : Analysis) -> @parser.ParseResult {
  self.parsed
}

///|
/// Return the semantic index built from the recovered syntax tree.
pub fn Analysis::semantic(self : Analysis) -> @semantic.SemanticIndex {
  self.semantic_index
}

///|
/// Return the number of modules recovered from the source text.
pub fn Analysis::module_count(self : Analysis) -> Int {
  self.parsed.module_count()
}

///|
/// Report whether parsing and semantic validation completed without blocking findings.
pub fn Analysis::is_valid(self : Analysis) -> Bool {
  self.parsed.is_valid() && self.semantic_index.release_ready()
}