File size: 1,546 Bytes
224e773
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//! AST validation and dangerous pattern detection

use super::nodes::AstNode;
use crate::Result;
use hyperkitty_core::Error;

/// Validate AST structure before construction
pub fn validate(nodes: &[AstNode], edges: &[(usize, usize)]) -> Result<()> {
    // Check for dangerous patterns
    for &(from_idx, to_idx) in edges {
        if from_idx >= nodes.len() || to_idx >= nodes.len() {
            return Err(Error::InvalidAST("Edge index out of bounds".to_string()));
        }

        let from = &nodes[from_idx];
        let to = &nodes[to_idx];

        if super::weights::has_dangerous_pattern(from, to) {
            return Err(Error::InvalidAST(format!(
                "Dangerous pattern: {} → {}",
                from.label, to.label
            )));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::nodes::NodeType;

    #[test]
    fn valid_ast() {
        let nodes = vec![
            AstNode::new(NodeType::Intent, "route"),
            AstNode::new(NodeType::Word, "hello"),
        ];
        let edges = vec![(0, 1)]; // structural → payload (OK)
        assert!(validate(&nodes, &edges).is_ok());
    }

    #[test]
    fn invalid_ast_dangerous() {
        let nodes = vec![
            AstNode::new(NodeType::Word, "hello"),
            AstNode::new(NodeType::Intent, "route"),
        ];
        let edges = vec![(0, 1)]; // payload → structural (BLOCKED)
        assert!(validate(&nodes, &edges).is_err());
    }
}