aldrin-parser 0.13.0

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

#[derive(Debug)]
pub(crate) struct InvalidEscapeCode {
    schema_name: String,
    ident: Ident,
    escape: String,
    span: Span,
}

impl InvalidEscapeCode {
    pub(crate) fn validate(def: &ConstDef, validate: &mut Validate) {
        let val = match def.value() {
            ConstValue::String(val) => val,
            _ => return,
        };

        let mut pos = val.span_inner().start;
        let mut chars = val.value_inner().chars().peekable();

        while let Some(c1) = chars.next() {
            if c1 == '\\' {
                let c2 = chars.next().unwrap();
                let len = 1 + c2.len_utf8();

                if (c2 != '\\') && (c2 != '"') {
                    validate.add_error(Self {
                        schema_name: validate.schema_name().to_owned(),
                        ident: def.name().clone(),
                        escape: format!("\\{c2}"),
                        span: Span {
                            start: pos,
                            end: pos + len,
                        },
                    });
                }

                pos += len;
            } else {
                pos += c1.len_utf8();
            }
        }
    }
}

impl Diagnostic for InvalidEscapeCode {
    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 escape code `{}` in string constant `{}`",
            self.escape,
            self.ident.value()
        ));

        if let Some(schema) = parser.get_schema(&self.schema_name) {
            report = report.snippet_with_context(
                schema,
                self.span,
                format!("invalid escape code `{}`", self.escape),
                self.ident.span(),
                "string constant defined here",
            );
        }

        report = report.help("only `\\\\` and `\\\"` are supported");
        report.render()
    }
}

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