ast_description_lang/ast/
mod.rs

1use crate::{Ident, InvalidIdent, Specs};
2use anyhow::{anyhow, Context, Result};
3use proc_macro2::TokenStream;
4use std::{
5  fmt::{self, Display, Formatter},
6  str::FromStr,
7};
8
9mod collapsed;
10mod lex;
11mod parsed;
12mod print;
13mod raw;
14
15pub fn generate_ast_mod(text: &str, specs: &Specs<'_>, config: &Config<'_>) -> Result<TokenStream> {
16  let error = TokenStream::from_str(config.error)
17    .map_err(|err| anyhow!("{err}"))
18    .context("failed to lex the error type")?;
19  let tokens_mod = TokenStream::from_str(config.tokens_mod)
20    .map_err(|err| anyhow!("{err}"))
21    .context("failed to lex the tokens mod path")?;
22  let span = match config.span {
23    Some(span) => Some(
24      TokenStream::from_str(span)
25        .map_err(|err| anyhow!("{err}"))
26        .context("failed to lex the span type")?,
27    ),
28    None => None,
29  };
30  let ast = raw::Ast::parse(text).context("failed to lex AST description")?;
31  let ast = ast
32    .transform(specs)
33    .context("failed to parse AST description")?;
34  let ast = ast
35    .transform()
36    .context("failed to collapse AST description")?;
37  let ast = ast.print(specs, error, tokens_mod, span);
38  Ok(ast)
39}
40
41#[non_exhaustive]
42pub struct Config<'c> {
43  pub error: &'c str,
44  pub tokens_mod: &'c str,
45  pub span: Option<&'c str>,
46}
47
48#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
49enum Modifier {
50  Repeat,
51  Csv,
52  OnePlus,
53  CsvOnePlus,
54  Optional,
55  Boxed,
56}
57
58impl<'i> Ident<'i> {
59  pub fn new(ident: &'i str) -> Result<Self, InvalidIdent> {
60    if ident.chars().all(|c| raw::IDENT_CHARS.contains(c)) {
61      Ok(Ident(ident))
62    } else {
63      Err(InvalidIdent(String::from(ident)))
64    }
65  }
66}
67
68impl Default for Config<'_> {
69  fn default() -> Self {
70    Self {
71      error: "::chumsky::error::Simple<Token>",
72      tokens_mod: "crate::tokens",
73      span: None,
74    }
75  }
76}
77
78impl Display for Modifier {
79  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
80    match self {
81      Modifier::Repeat => write!(f, "*"),
82      Modifier::Csv => write!(f, ",*"),
83      Modifier::OnePlus => write!(f, "+"),
84      Modifier::CsvOnePlus => write!(f, ",+"),
85      Modifier::Optional => write!(f, "?"),
86      Modifier::Boxed => write!(f, "~"),
87    }
88  }
89}