aldrin_parser/error/
invalid_array_len.rs1use 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}