ast_description_lang/
lib.rs1pub use self::{
2 ast::*,
3 collections::{NamedItem, NamedSet, Unnamed},
4};
5use heck::ToPascalCase;
6use indexmap::IndexMap;
7use serde::Deserialize;
8use std::fmt::{Display, Formatter};
9use thiserror::Error;
10
11mod ast;
12mod collections;
13mod tokens;
14
15#[derive(Clone, Debug, Deserialize)]
16#[serde(bound(deserialize = "'de: 's"))]
17pub struct Specs<'s> {
18 pub static_tokens: IndexMap<Ident<'s>, &'s str>,
19 pub dynamic_tokens: IndexMap<Ident<'s>, &'s str>,
20 pub delimiters: IndexMap<Ident<'s>, Delimiter<'s>>,
21}
22
23#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize)]
24#[serde(transparent)]
25pub struct Ident<'a>(&'a str);
26
27#[derive(Copy, Clone, Debug, Deserialize)]
28pub struct Delimiter<'d> {
29 open: &'d str,
30 close: &'d str,
31}
32
33impl<'i> Ident<'i> {
34 pub fn as_type(&self) -> proc_macro2::Ident {
35 quote::format_ident!("{}", self.0.to_pascal_case())
36 }
37}
38
39impl Display for Ident<'_> {
40 #[inline(always)]
41 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42 Display::fmt(self.0, f)
43 }
44}
45
46#[derive(Clone, Debug, Error)]
47#[error("invalid ident: {0}")]
48pub struct InvalidIdent(String);
49
50fn is_rust_keyword(word: &str) -> bool {
51 #[rustfmt::skip]
52 const KEYWORDS: &[&str] = &[
53 "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
55 "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
56 "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type",
57 "unsafe", "use", "where", "while",
58
59 "abstract", "become", "box", "do", "final", "macro", "override", "priv", "try", "typeof",
61 "unsized", "virtual", "yield",
62 ];
63
64 KEYWORDS.contains(&word)
65}
66
67#[cfg(test)]
68#[allow(clippy::type_complexity)]
69const SNAPSHOT_CASES: &[&str] = &["json", "foo"];