aldrin-parser 0.13.0

Aldrin schema parser library.
Documentation
use super::{Error, ErrorKind};
use crate::ast::{ArrayLen, ArrayLenValue, ConstValue, Ident, NamedRefKind};
use crate::diag::{Diagnostic, DiagnosticKind, Renderer};
use crate::validate::Validate;
use crate::Parser;

#[derive(Debug)]
pub(crate) struct InvalidArrayLen {
    schema_name: String,
    len: ArrayLen,
    value: String,
    const_def: Option<(String, Ident)>,
}

impl InvalidArrayLen {
    pub(crate) fn validate(len: &ArrayLen, validate: &mut Validate) {
        let (value, const_def) = match len.value() {
            ArrayLenValue::Literal(lit) => (lit.value(), None),

            ArrayLenValue::Ref(named_ref) => {
                let (schema, ident) = match named_ref.kind() {
                    NamedRefKind::Intern(ident) => (validate.get_current_schema(), ident),

                    NamedRefKind::Extern(schema, ident) => {
                        let Some(schema) = validate.get_schema(schema.value()) else {
                            return;
                        };

                        (schema, ident)
                    }
                };

                let mut res = None;
                for def in schema.definitions() {
                    let Some(const_def) = def.as_const() else {
                        continue;
                    };

                    if const_def.name().value() != ident.value() {
                        continue;
                    }

                    if res.is_some() {
                        return;
                    }

                    match const_def.value() {
                        ConstValue::U8(lit)
                        | ConstValue::I8(lit)
                        | ConstValue::U16(lit)
                        | ConstValue::I16(lit)
                        | ConstValue::U32(lit)
                        | ConstValue::I32(lit)
                        | ConstValue::U64(lit)
                        | ConstValue::I64(lit) => {
                            res = Some((lit.value(), Some((schema.name(), const_def.name()))))
                        }

                        ConstValue::String(_) | ConstValue::Uuid(_) => return,
                    }
                }

                if let Some(res) = res {
                    res
                } else {
                    return;
                }
            }
        };

        if value.parse::<u32>().ok().map(|v| v == 0).unwrap_or(true) {
            validate.add_error(Self {
                schema_name: validate.schema_name().to_owned(),
                len: len.clone(),
                value: value.to_owned(),
                const_def: const_def.map(|(s, i)| (s.to_owned(), i.clone())),
            });
        }
    }
}

impl Diagnostic for InvalidArrayLen {
    fn kind(&self) -> DiagnosticKind {
        DiagnosticKind::Error
    }

    fn schema_name(&self) -> &str {
        &self.schema_name
    }

    fn render(&self, renderer: &Renderer, parser: &Parser) -> String {
        let mut report = renderer.error(format!("invalid array length {}", self.value));

        if let Some(schema) = parser.get_schema(&self.schema_name) {
            report = report.snippet(schema, self.len.span(), "array length used here");
        }

        if let Some((ref schema, ref ident)) = self.const_def {
            if let Some(schema) = parser.get_schema(schema) {
                report = report.context(schema, ident.span(), "constant defined here");
            }
        }

        report = report.help("arrays must have a length in the range from 1 to 4294967295");
        report.render()
    }
}

impl From<InvalidArrayLen> for Error {
    fn from(e: InvalidArrayLen) -> Self {
        Self {
            kind: ErrorKind::InvalidArrayLen(e),
        }
    }
}