ast_description_lang/
lib.rs

1pub 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    // strict keywords
54    "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    // reserved keywords
60    "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"];