aldrin_parser/error/
invalid_array_len.rs

1use super::Error;
2use crate::ast::{ArrayLen, ArrayLenValue, ConstValue, Ident, NamedRefKind};
3use crate::diag::{Diagnostic, DiagnosticKind, Formatted, Formatter};
4use crate::validate::Validate;
5use crate::Parsed;
6
7#[derive(Debug)]
8pub struct InvalidArrayLen {
9    schema_name: String,
10    len: ArrayLen,
11    value: String,
12    const_def: Option<(String, Ident)>,
13}
14
15impl InvalidArrayLen {
16    pub(crate) fn validate(len: &ArrayLen, validate: &mut Validate) {
17        let (value, const_def) = match len.value() {
18            ArrayLenValue::Literal(lit) => (lit.value(), None),
19
20            ArrayLenValue::Ref(named_ref) => {
21                let (schema, ident) = match named_ref.kind() {
22                    NamedRefKind::Intern(ident) => (validate.get_current_schema(), ident),
23
24                    NamedRefKind::Extern(schema, ident) => {
25                        let Some(schema) = validate.get_schema(schema.value()) else {
26                            return;
27                        };
28
29                        (schema, ident)
30                    }
31                };
32
33                let mut res = None;
34                for def in schema.definitions() {
35                    let Some(const_def) = def.as_const() else {
36                        continue;
37                    };
38
39                    if const_def.name().value() != ident.value() {
40                        continue;
41                    }
42
43                    if res.is_some() {
44                        return;
45                    }
46
47                    match const_def.value() {
48                        ConstValue::U8(lit)
49                        | ConstValue::I8(lit)
50                        | ConstValue::U16(lit)
51                        | ConstValue::I16(lit)
52                        | ConstValue::U32(lit)
53                        | ConstValue::I32(lit)
54                        | ConstValue::U64(lit)
55                        | ConstValue::I64(lit) => {
56                            res = Some((lit.value(), Some((schema.name(), const_def.name()))))
57                        }
58
59                        ConstValue::String(_) | ConstValue::Uuid(_) => return,
60                    }
61                }
62
63                if let Some(res) = res {
64                    res
65                } else {
66                    return;
67                }
68            }
69        };
70
71        if value.parse::<u32>().ok().map(|v| v == 0).unwrap_or(true) {
72            validate.add_error(Self {
73                schema_name: validate.schema_name().to_owned(),
74                len: len.clone(),
75                value: value.to_owned(),
76                const_def: const_def.map(|(s, i)| (s.to_owned(), i.clone())),
77            });
78        }
79    }
80
81    pub fn len(&self) -> &ArrayLen {
82        &self.len
83    }
84
85    pub fn value(&self) -> &str {
86        &self.value
87    }
88
89    pub fn const_def(&self) -> Option<(&str, &Ident)> {
90        self.const_def.as_ref().map(|(s, i)| (s.as_str(), i))
91    }
92}
93
94impl Diagnostic for InvalidArrayLen {
95    fn kind(&self) -> DiagnosticKind {
96        DiagnosticKind::Error
97    }
98
99    fn schema_name(&self) -> &str {
100        &self.schema_name
101    }
102
103    fn format<'a>(&'a self, parsed: &'a Parsed) -> Formatted<'a> {
104        let mut fmt = Formatter::new(self, format!("invalid array length {}", self.value));
105
106        if let Some(schema) = parsed.get_schema(&self.schema_name) {
107            fmt.main_block(
108                schema,
109                self.len.span().from,
110                self.len.span(),
111                "array length used here",
112            );
113        }
114
115        if let Some((ref schema, ref ident)) = self.const_def {
116            if let Some(schema) = parsed.get_schema(schema) {
117                fmt.info_block(
118                    schema,
119                    ident.span().from,
120                    ident.span(),
121                    "constant defined here",
122                );
123            }
124        }
125
126        fmt.help("arrays must have a length in the range from 1 to 4294967295");
127        fmt.format()
128    }
129}
130
131impl From<InvalidArrayLen> for Error {
132    fn from(e: InvalidArrayLen) -> Self {
133        Self::InvalidArrayLen(e)
134    }
135}