pidgin-lang 0.1.10

A compact agent handoff protocol runtime — parse, validate, resolve, and expand Pidgin packets
Documentation
use crate::ast::{Directive, FieldValue, PgnPacket};
use super::ValidationError;

pub fn validate_syntax(packet: &PgnPacket) -> Vec<ValidationError> {
    let mut errors = Vec::new();

    match packet.directive {
        Directive::Run => {
            require_field(packet, "wf", &mut errors);
            require_field(packet, "mode", &mut errors);
            require_list_field(packet, "in", &mut errors);
            require_list_field(packet, "out", &mut errors);
        }
        Directive::Result => {
            require_field(packet, "wf", &mut errors);
            require_list_field(packet, "out", &mut errors);
            require_field(packet, "status", &mut errors);
        }
        Directive::Approval => {
            require_field(packet, "status", &mut errors);
        }
        Directive::Context => {
            require_field(packet, "wf", &mut errors);
            require_list_field(packet, "in", &mut errors);
        }
    }

    errors
}

fn require_field(packet: &PgnPacket, field: &str, errors: &mut Vec<ValidationError>) {
    if !packet.fields.contains_key(field) {
        errors.push(ValidationError {
            code: "PGN_E001".to_string(),
            message: format!("missing required field: {}", field),
        });
    }
}

fn require_list_field(packet: &PgnPacket, field: &str, errors: &mut Vec<ValidationError>) {
    match packet.fields.get(field) {
        None => {
            errors.push(ValidationError {
                code: "PGN_E001".to_string(),
                message: format!("missing required field: {}", field),
            });
        }
        Some(value) => {
            if !matches!(value, FieldValue::List(_)) {
                errors.push(ValidationError {
                    code: "PGN_E016".to_string(),
                    message: format!("field '{}' must be a list, got scalar", field),
                });
            }
        }
    }
}