use crate::hir::{BodyOwnerKind, HirBodyId, HirFile};
use crate::pir::lower::lower_single_body;
use crate::pir::model::{LexicalName, PirOperation, PirSourceAnchor};
pub const LEXICAL_EXTRACTOR_RECEIPT_VERSION: u32 = 1;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct LexicalBindingFact {
pub name: LexicalName,
pub role: LexicalRole,
pub source_anchor: PirSourceAnchor,
pub body_idx: usize,
pub body_owner: BodyOwnerKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum LexicalRole {
Read,
Write,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct BodyExtractionResult {
pub body_idx: usize,
pub owner: BodyOwnerKind,
pub facts: Vec<LexicalBindingFact>,
pub anchored_node_count: usize,
pub total_node_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct LexicalExtractorReceipt {
pub schema_version: u32,
pub bodies: Vec<BodyExtractionResult>,
pub total_read_count: usize,
pub total_write_count: usize,
pub skipped_node_count: usize,
pub provider_behavior_changed: bool,
}
#[must_use]
pub fn extract_lexical_facts(file: &HirFile) -> LexicalExtractorReceipt {
let mut bodies = Vec::new();
let mut total_read_count = 0usize;
let mut total_write_count = 0usize;
let mut skipped_node_count = 0usize;
for (body_idx, body) in file.bodies.iter().enumerate() {
let owner = body.owner.clone();
let mut facts = Vec::new();
let mut anchored_node_count = 0usize;
let mut total_node_count = 0usize;
let pir_nodes = lower_single_body(body, HirBodyId(body_idx as u32), file);
for pir_node in pir_nodes {
total_node_count += 1;
match &pir_node.operation {
PirOperation::LexicalRead { name } => {
if pir_node.source_anchor.is_anchored() {
anchored_node_count += 1;
facts.push(LexicalBindingFact {
name: name.clone(),
role: LexicalRole::Read,
source_anchor: pir_node.source_anchor.clone(),
body_idx,
body_owner: owner.clone(),
});
total_read_count += 1;
}
}
PirOperation::LexicalWrite { name } => {
if pir_node.source_anchor.is_anchored() {
anchored_node_count += 1;
facts.push(LexicalBindingFact {
name: name.clone(),
role: LexicalRole::Write,
source_anchor: pir_node.source_anchor.clone(),
body_idx,
body_owner: owner.clone(),
});
total_write_count += 1;
}
}
PirOperation::Modify { .. } | PirOperation::StashModify { .. } => {
skipped_node_count += 1;
}
_ => {}
}
}
bodies.push(BodyExtractionResult {
body_idx,
owner,
facts,
anchored_node_count,
total_node_count,
});
}
LexicalExtractorReceipt {
schema_version: LEXICAL_EXTRACTOR_RECEIPT_VERSION,
bodies,
total_read_count,
total_write_count,
skipped_node_count,
provider_behavior_changed: false,
}
}