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
|
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) {
|
fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
||||||
match node {
|
match node {
|
||||||
StepNode::Block(nodes) => {
|
StepNode::Block(nodes) => {
|
||||||
@ -481,18 +481,23 @@ fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
|||||||
}
|
}
|
||||||
StepNode::If {
|
StepNode::If {
|
||||||
cond,
|
cond,
|
||||||
|
cond_ast,
|
||||||
then_branch,
|
then_branch,
|
||||||
else_branch,
|
else_branch,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
facts.add_cond_sig(cond.to_compact_string());
|
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);
|
walk_for_facts(then_branch, facts);
|
||||||
if let Some(else_branch) = else_branch {
|
if let Some(else_branch) = else_branch {
|
||||||
walk_for_facts(else_branch, facts);
|
walk_for_facts(else_branch, facts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StepNode::Loop { cond, body, .. } => {
|
StepNode::Loop { cond, cond_ast, body, .. } => {
|
||||||
facts.add_cond_sig(cond.to_compact_string());
|
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);
|
walk_for_facts(body, facts);
|
||||||
}
|
}
|
||||||
StepNode::Stmt { kind, .. } => {
|
StepNode::Stmt { kind, .. } => {
|
||||||
@ -506,10 +511,16 @@ fn walk_for_facts(node: &StepNode, facts: &mut StepTreeFacts) {
|
|||||||
if let Some(name) = target.as_ref() {
|
if let Some(name) = target.as_ref() {
|
||||||
facts.add_write(name.clone());
|
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::Print => {}
|
||||||
StepStmtKind::Return { .. } => {
|
StepStmtKind::Return { value_ast } => {
|
||||||
facts.add_exit(ExitKind::Return);
|
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 => {
|
StepStmtKind::Break => {
|
||||||
facts.add_exit(ExitKind::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 {
|
fn merge_features(mut a: StepTreeFeatures, b: StepTreeFeatures) -> StepTreeFeatures {
|
||||||
a.has_if |= b.has_if;
|
a.has_if |= b.has_if;
|
||||||
a.has_loop |= b.has_loop;
|
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:
|
//! 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
|
//! - NO formatting, NO decision-making, NO signature generation
|
||||||
//! - Pure "facts only" - data collection without interpretation
|
//! - Pure "facts only" - data collection without interpretation
|
||||||
//!
|
//!
|
||||||
@ -9,6 +9,10 @@
|
|||||||
//! - Facts are collected during tree traversal
|
//! - Facts are collected during tree traversal
|
||||||
//! - BTreeSet for deterministic iteration (order stability)
|
//! - BTreeSet for deterministic iteration (order stability)
|
||||||
//! - No dependency on contract or signature logic
|
//! - 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 crate::mir::control_tree::{ExitKind, StepCapability};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
@ -20,6 +24,9 @@ pub struct StepTreeFacts {
|
|||||||
pub exits: BTreeSet<ExitKind>,
|
pub exits: BTreeSet<ExitKind>,
|
||||||
/// Variable writes (Local declarations + Assignment targets)
|
/// Variable writes (Local declarations + Assignment targets)
|
||||||
pub writes: BTreeSet<String>,
|
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.)
|
/// Required capabilities (structural features like NestedLoop, TryCatch, etc.)
|
||||||
pub required_caps: BTreeSet<StepCapability>,
|
pub required_caps: BTreeSet<StepCapability>,
|
||||||
/// Condition signatures (compact string representations of if/loop conditions)
|
/// Condition signatures (compact string representations of if/loop conditions)
|
||||||
@ -43,6 +50,11 @@ impl StepTreeFacts {
|
|||||||
self.writes.insert(var);
|
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
|
/// Add a required capability
|
||||||
pub fn add_capability(&mut self, cap: StepCapability) {
|
pub fn add_capability(&mut self, cap: StepCapability) {
|
||||||
self.required_caps.insert(cap);
|
self.required_caps.insert(cap);
|
||||||
@ -57,6 +69,7 @@ impl StepTreeFacts {
|
|||||||
pub fn merge(&mut self, other: StepTreeFacts) {
|
pub fn merge(&mut self, other: StepTreeFacts) {
|
||||||
self.exits.extend(other.exits);
|
self.exits.extend(other.exits);
|
||||||
self.writes.extend(other.writes);
|
self.writes.extend(other.writes);
|
||||||
|
self.reads.extend(other.reads); // Phase 124: merge reads
|
||||||
self.required_caps.extend(other.required_caps);
|
self.required_caps.extend(other.required_caps);
|
||||||
self.cond_sig.extend(other.cond_sig);
|
self.cond_sig.extend(other.cond_sig);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user