idl 0.1.1

Library used for the idl language.
Documentation
use super::range::Range;
use regex::Regex;
use std::fmt;
use thiserror::Error;

static RESERVED: &'static [&str] = &[
    "abstract",
    "as",
    "asm",
    "assert",
    "async",
    "auto",
    "await",
    "become",
    "begin",
    "box",
    "break",
    "case",
    "catch",
    "class",
    "contexpr",
    "continue",
    "covariant",
    "crate",
    "decltype",
    "def",
    "default",
    "deferred",
    "define",
    "delete",
    "do",
    "dyn",
    "dynamic",
    "else",
    "end",
    "exception",
    "explicit",
    "export",
    "extends",
    "extension",
    "extern",
    "external",
    "false",
    "final",
    "finally",
    "fn",
    "for",
    "friend",
    "get",
    "goto",
    "hashcode",
    "hide",
    "if",
    "impl",
    "implements",
    "in",
    "inline",
    "instance",
    "is",
    "let",
    "loop",
    "macro",
    "match",
    "mixin",
    "move",
    "mut",
    "mutable",
    "new",
    "nil",
    "noexpect",
    "nosuchfunction",
    "null",
    "nullptr",
    "on",
    "operator",
    "option",
    "out",
    "override",
    "part",
    "pin",
    "priv",
    "private",
    "protected",
    "pub",
    "public",
    "ref",
    "register",
    "result",
    "rethrow",
    "return",
    "runtimetype",
    "self",
    "service",
    "set",
    "short",
    "show",
    "signed",
    "sizeof",
    "static",
    "structure",
    "super",
    "switch",
    "sync",
    "this",
    "throw",
    "time",
    "tostring",
    "trait",
    "true",
    "try",
    "tuple",
    "typedef",
    "typeof",
    "union",
    "unsafe",
    "unsigned",
    "unsized",
    "use",
    "var",
    "version",
    "virtual",
    "void",
    "volatile",
    "where",
    "while",
    "with",
    "yield",
];

static RESERVED_TYPES: &'static [&str] = &[
    "void", "uint", "time", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128",
    "f16", "f32", "f64", "f128", "double", "decimal", "date", "char",
];

#[derive(Error, Debug, Clone)]
pub struct NameError(
    pub(super) NameErrorKind,
    pub(super) Range,
    pub(super) String,
);

#[derive(Debug, Copy, Clone)]
pub enum NameErrorKind {
    InvalidFieldName,
    InvalidTypeName,
    ReservedName,
    ReservedType,
}

impl fmt::Display for NameError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let errstr = match &self.0 {
            NameErrorKind::InvalidFieldName => format!("Invalid field name `{}`", self.2),
            NameErrorKind::InvalidTypeName => format!("Invalid type name `{}`", self.2),
            NameErrorKind::ReservedName => format!("Reserved name `{}`", self.2),
            NameErrorKind::ReservedType => format!("Reserved type `{}`", self.2),
        };

        write!(f, "{}", errstr)
    }
}

pub(super) fn type_name_is_valid(name: &str, range: Range) -> Result<(), NameError> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^[A-Z]+[A-Za-z0-9]*$").unwrap();
    }

    if RE.is_match(name) {
        Ok(())
    } else {
        Err(NameError(
            NameErrorKind::InvalidTypeName,
            range,
            name.to_owned(),
        ))
    }
}

pub(super) fn field_name_is_valid(name: &str, range: Range) -> Result<(), NameError> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^((?:[a-z]+[0-9]*)+(?:[A-Za-z0-9]+)*)$").unwrap();
    }

    if RE.is_match(name) {
        Ok(())
    } else {
        Err(NameError(
            NameErrorKind::InvalidFieldName,
            range,
            name.to_owned(),
        ))
    }
}

pub(super) fn is_reserved_word(name: &str, range: Range) -> Result<(), NameError> {
    if RESERVED.contains(&name) {
        Err(NameError(
            NameErrorKind::ReservedName,
            range,
            name.to_owned(),
        ))
    } else {
        Ok(())
    }
}

pub(super) fn is_reserved_type(name: &str, range: Range) -> Result<(), NameError> {
    if RESERVED_TYPES.contains(&name) {
        Err(NameError(
            NameErrorKind::ReservedType,
            range,
            name.to_owned(),
        ))
    } else {
        Ok(())
    }
}