pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
// Stack analysis and invariant checking for WASM verification

impl InvariantChecker {
    fn new() -> Self {
        Self {
            invariants: vec![
                SafetyInvariant::MemoryBounds,
                SafetyInvariant::StackBalance,
                SafetyInvariant::TypeSafety,
                SafetyInvariant::NoIntegerOverflow,
            ],
        }
    }

    #[allow(dead_code)]
    fn check_all(&self, _module: &[u8]) -> Vec<InvariantViolation> {
        // Check each invariant
        Vec::new()
    }
}

impl StackAnalyzer {
    fn new() -> Self {
        Self {
            type_stack: Vec::new(),
        }
    }

    fn update_stack(&self, stack: &mut Vec<ValType>, op: &Operator) -> Result<()> {
        match op {
            // Constants push their type
            Operator::I32Const { .. } => stack.push(ValType::I32),
            Operator::I64Const { .. } => stack.push(ValType::I64),
            Operator::F32Const { .. } => stack.push(ValType::F32),
            Operator::F64Const { .. } => stack.push(ValType::F64),

            // Binary i32 operations
            Operator::I32Add
            | Operator::I32Sub
            | Operator::I32Mul
            | Operator::I32DivS
            | Operator::I32DivU => {
                pop_binary_i32(stack)?;
            }

            // Binary i64 operations
            Operator::I64Add
            | Operator::I64Sub
            | Operator::I64Mul
            | Operator::I64DivS
            | Operator::I64DivU => {
                pop_binary_i64(stack)?;
            }

            // Comparisons
            Operator::I32Eqz => {
                if stack.pop() != Some(ValType::I32) {
                    return Err(anyhow!("Type error: expected i32"));
                }
                stack.push(ValType::I32);
            }

            Operator::I32Eq
            | Operator::I32Ne
            | Operator::I32LtS
            | Operator::I32LtU
            | Operator::I32GtS
            | Operator::I32GtU => {
                pop_comparison_i32(stack)?;
            }

            // Local operations
            Operator::LocalGet { local_index: _ } => {
                // Would need local types from function signature
                stack.push(ValType::I32); // Simplified
            }

            Operator::LocalSet { local_index: _ } => {
                if stack.is_empty() {
                    return Err(anyhow!("Stack underflow"));
                }
                stack.pop();
            }

            Operator::Drop => {
                if stack.is_empty() {
                    return Err(anyhow!("Stack underflow"));
                }
                stack.pop();
            }

            _ => {} // Other operators
        }

        Ok(())
    }
}

/// Pop two i32 operands, push i32 result. Returns Err on stack underflow.
fn pop_binary_i32(stack: &mut Vec<ValType>) -> Result<()> {
    if stack.len() < 2 {
        return Err(anyhow!("Stack underflow"));
    }
    stack.pop();
    stack.pop();
    stack.push(ValType::I32);
    Ok(())
}

/// Pop two i64 operands, push i64 result. Returns Err on stack underflow.
fn pop_binary_i64(stack: &mut Vec<ValType>) -> Result<()> {
    if stack.len() < 2 {
        return Err(anyhow!("Stack underflow"));
    }
    stack.pop();
    stack.pop();
    stack.push(ValType::I64);
    Ok(())
}

/// Pop two i32 operands for comparison, push i32 result. Returns Err on stack underflow or type error.
fn pop_comparison_i32(stack: &mut Vec<ValType>) -> Result<()> {
    if stack.len() < 2 {
        return Err(anyhow!("Stack underflow"));
    }
    if stack.pop() != Some(ValType::I32) || stack.pop() != Some(ValType::I32) {
        return Err(anyhow!("Type error: expected i32"));
    }
    stack.push(ValType::I32);
    Ok(())
}