pidgin_lang/validator/
syntax.rs1use crate::ast::{Directive, FieldValue, PgnPacket};
2use super::ValidationError;
3
4pub fn validate_syntax(packet: &PgnPacket) -> Vec<ValidationError> {
5 let mut errors = Vec::new();
6
7 match packet.directive {
8 Directive::Run => {
9 require_field(packet, "wf", &mut errors);
10 require_field(packet, "mode", &mut errors);
11 require_list_field(packet, "in", &mut errors);
12 require_list_field(packet, "out", &mut errors);
13 }
14 Directive::Result => {
15 require_field(packet, "wf", &mut errors);
16 require_list_field(packet, "out", &mut errors);
17 require_field(packet, "status", &mut errors);
18 }
19 Directive::Approval => {
20 require_field(packet, "status", &mut errors);
21 }
22 Directive::Context => {
23 require_field(packet, "wf", &mut errors);
24 require_list_field(packet, "in", &mut errors);
25 }
26 }
27
28 errors
29}
30
31fn require_field(packet: &PgnPacket, field: &str, errors: &mut Vec<ValidationError>) {
32 if !packet.fields.contains_key(field) {
33 errors.push(ValidationError {
34 code: "PGN_E001".to_string(),
35 message: format!("missing required field: {}", field),
36 });
37 }
38}
39
40fn require_list_field(packet: &PgnPacket, field: &str, errors: &mut Vec<ValidationError>) {
41 match packet.fields.get(field) {
42 None => {
43 errors.push(ValidationError {
44 code: "PGN_E001".to_string(),
45 message: format!("missing required field: {}", field),
46 });
47 }
48 Some(value) => {
49 if !matches!(value, FieldValue::List(_)) {
50 errors.push(ValidationError {
51 code: "PGN_E016".to_string(),
52 message: format!("field '{}' must be a list, got scalar", field),
53 });
54 }
55 }
56 }
57}