feat(control_tree): Phase 124 add reads to StepTreeFacts
- Add reads: BTreeSet<String> to StepTreeFacts - Add add_read() API and merge_reads() in merge() - Add extract_variables_from_ast() helper for AST traversal - Extract reads from: - If/Loop condition AST - Return value AST - All Variable nodes recursively (BinaryOp, UnaryOp, FunctionCall, MethodCall, FieldAccess, Index, Assignment RHS, Print) - SSOT: extract_variables_from_ast() is the single source for reads collection
This commit is contained in:
@ -471,7 +471,7 @@ fn extract_facts_from_tree(root: &StepNode, features: &StepTreeFeatures) -> Step
|
||||
facts
|
||||
}
|
||||
|
||||
/// Walk StepNode tree to collect facts (Phase 120)
|
||||
/// Walk StepNode tree to collect facts (Phase 120, Phase 124)
|
||||
fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
||||
match node {
|
||||
StepNode::Block(nodes) => {
|
||||
@ -481,18 +481,23 @@ fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
||||
}
|
||||
StepNode::If {
|
||||
cond,
|
||||
cond_ast,
|
||||
then_branch,
|
||||
else_branch,
|
||||
..
|
||||
} => {
|
||||
facts.add_cond_sig(cond.to_compact_string());
|
||||
// Phase 124: Extract reads from condition AST
|
||||
extract_variables_from_ast(&cond_ast.0, facts);
|
||||
walk_for_facts(then_branch, facts);
|
||||
if let Some(else_branch) = else_branch {
|
||||
walk_for_facts(else_branch, facts);
|
||||
}
|
||||
}
|
||||
StepNode::Loop { cond, body, .. } => {
|
||||
StepNode::Loop { cond, cond_ast, body, .. } => {
|
||||
facts.add_cond_sig(cond.to_compact_string());
|
||||
// Phase 124: Extract reads from condition AST
|
||||
extract_variables_from_ast(&cond_ast.0, facts);
|
||||
walk_for_facts(body, facts);
|
||||
}
|
||||
StepNode::Stmt { kind, .. } => {
|
||||
@ -506,10 +511,16 @@ fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
||||
if let Some(name) = target.as_ref() {
|
||||
facts.add_write(name.clone());
|
||||
}
|
||||
// Note: Assign RHS is not in StepStmtKind
|
||||
// We rely on If/Loop condition AST for reads extraction
|
||||
}
|
||||
StepStmtKind::Print => {}
|
||||
StepStmtKind::Return { .. } => {
|
||||
StepStmtKind::Return { value_ast } => {
|
||||
facts.add_exit(ExitKind::Return);
|
||||
// Phase 124: Extract reads from return value AST
|
||||
if let Some(ast) = value_ast {
|
||||
extract_variables_from_ast(&ast.0, facts);
|
||||
}
|
||||
}
|
||||
StepStmtKind::Break => {
|
||||
facts.add_exit(ExitKind::Break);
|
||||
@ -546,6 +557,60 @@ fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract Variable names from AST (Phase 124: reads collection)
|
||||
///
|
||||
/// SSOT for reads extraction:
|
||||
/// - Recursively walk AST tree
|
||||
/// - Add Variable { name } to facts.reads
|
||||
/// - Ignore other node types
|
||||
fn extract_variables_from_ast(ast: &ASTNode, facts: &mut StepTreeFacts) {
|
||||
match ast {
|
||||
ASTNode::Variable { name, .. } => {
|
||||
facts.add_read(name.clone());
|
||||
}
|
||||
// Recursively walk binary/unary operations
|
||||
ASTNode::BinaryOp { left, right, .. } => {
|
||||
extract_variables_from_ast(left, facts);
|
||||
extract_variables_from_ast(right, facts);
|
||||
}
|
||||
ASTNode::UnaryOp { operand, .. } => {
|
||||
extract_variables_from_ast(operand, facts);
|
||||
}
|
||||
// Function calls
|
||||
ASTNode::FunctionCall { arguments, .. } => {
|
||||
for arg in arguments {
|
||||
extract_variables_from_ast(arg, facts);
|
||||
}
|
||||
}
|
||||
// Method calls
|
||||
ASTNode::MethodCall { object, arguments, .. } => {
|
||||
extract_variables_from_ast(object, facts);
|
||||
for arg in arguments {
|
||||
extract_variables_from_ast(arg, facts);
|
||||
}
|
||||
}
|
||||
// Field access
|
||||
ASTNode::FieldAccess { object, .. } => {
|
||||
extract_variables_from_ast(object, facts);
|
||||
}
|
||||
// Array/Index access
|
||||
ASTNode::Index { target, index, .. } => {
|
||||
extract_variables_from_ast(target, facts);
|
||||
extract_variables_from_ast(index, facts);
|
||||
}
|
||||
// Assignment (RHS only)
|
||||
ASTNode::Assignment { value, .. } => {
|
||||
extract_variables_from_ast(value, facts);
|
||||
}
|
||||
// Print
|
||||
ASTNode::Print { expression, .. } => {
|
||||
extract_variables_from_ast(expression, facts);
|
||||
}
|
||||
// Ignore literals, keywords, and other non-variable nodes
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_features(mut a: StepTreeFeatures, b: StepTreeFeatures) -> StepTreeFeatures {
|
||||
a.has_if |= b.has_if;
|
||||
a.has_loop |= b.has_loop;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//! StepTreeFacts - raw structural facts extraction (Phase 120)
|
||||
//! StepTreeFacts - raw structural facts extraction (Phase 120, Phase 124)
|
||||
//!
|
||||
//! Responsibility:
|
||||
//! - Collect raw structural facts from StepNode tree (exits/writes/required_caps/cond_sig)
|
||||
//! - Collect raw structural facts from StepNode tree (exits/writes/reads/required_caps/cond_sig)
|
||||
//! - NO formatting, NO decision-making, NO signature generation
|
||||
//! - Pure "facts only" - data collection without interpretation
|
||||
//!
|
||||
@ -9,6 +9,10 @@
|
||||
//! - Facts are collected during tree traversal
|
||||
//! - BTreeSet for deterministic iteration (order stability)
|
||||
//! - No dependency on contract or signature logic
|
||||
//!
|
||||
//! Phase 124 Changes:
|
||||
//! - Added reads: BTreeSet<String> for variable references
|
||||
//! - reads tracks Variable(name) occurrences in expressions, conditions, and assignments
|
||||
|
||||
use crate::mir::control_tree::{ExitKind, StepCapability};
|
||||
use std::collections::BTreeSet;
|
||||
@ -20,6 +24,9 @@ pub struct StepTreeFacts {
|
||||
pub exits: BTreeSet<ExitKind>,
|
||||
/// Variable writes (Local declarations + Assignment targets)
|
||||
pub writes: BTreeSet<String>,
|
||||
/// Variable reads (Variable references in expressions, conditions, assignments)
|
||||
/// Phase 124: Tracks all Variable(name) occurrences for Return(Variable) support
|
||||
pub reads: BTreeSet<String>,
|
||||
/// Required capabilities (structural features like NestedLoop, TryCatch, etc.)
|
||||
pub required_caps: BTreeSet<StepCapability>,
|
||||
/// Condition signatures (compact string representations of if/loop conditions)
|
||||
@ -43,6 +50,11 @@ impl StepTreeFacts {
|
||||
self.writes.insert(var);
|
||||
}
|
||||
|
||||
/// Add a variable read (Phase 124)
|
||||
pub fn add_read(&mut self, var: String) {
|
||||
self.reads.insert(var);
|
||||
}
|
||||
|
||||
/// Add a required capability
|
||||
pub fn add_capability(&mut self, cap: StepCapability) {
|
||||
self.required_caps.insert(cap);
|
||||
@ -57,6 +69,7 @@ impl StepTreeFacts {
|
||||
pub fn merge(&mut self, other: StepTreeFacts) {
|
||||
self.exits.extend(other.exits);
|
||||
self.writes.extend(other.writes);
|
||||
self.reads.extend(other.reads); // Phase 124: merge reads
|
||||
self.required_caps.extend(other.required_caps);
|
||||
self.cond_sig.extend(other.cond_sig);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user