1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//! # teleparse-macros
//!
//! These are for use with the [`teleparse`](https://docs.rs/teleparse) crate and not meant to be used standalone.

mod prelude;
use prelude::*;
use regex::Regex;

mod lexer_derive_impl;
mod token_type_derive_impl;
mod syntax_tree_derive_impl;

/// Derive trait from teleparse along with other required traits
#[proc_macro_attribute]
pub fn teleparse_derive(attr: TokenStream, input: TokenStream) -> TokenStream {
    let ident = parse_macro_input!(attr as syn::Ident);
    match teleparse_derive_internal(&ident, input) {
        Ok(out) => out,
        Err(err) => err.into_compile_error().into(),
    }
}

fn teleparse_derive_internal(ident: &syn::Ident, input: TokenStream) -> syn::Result<TokenStream> {
    let out = match ident.to_string().as_str() {
        "TokenType" => {
            token_type_derive_impl::expand(input, ident)
        },
        "Lexer" => {
            lexer_derive_impl::expand(input, ident)
        },
        "SyntaxTree" => {
            syntax_tree_derive_impl::expand(input, ident)
        },
        _ => syn_error!(ident, "unknown llnparse_derive input `{}`", ident),
    };

    Ok(out)
}

// /// Used internally in `llnparse` to ensure that a regex literal is valid
// #[proc_macro]
// pub fn checked_regex_rule(input: TokenStream) -> TokenStream {
//     let regex = {
//         let input = input.clone();
//         parse_macro_input!(input as syn::LitStr)
//     };
//     let result = checked_regex_rule_internal(&regex);
//     from_result_keep_input(quote!{#regex}, result)
// }
//
// fn checked_regex_rule_internal(input: &syn::LitStr) -> syn::Result<TokenStream2> {
//     let regex = input.value();
//     if !regex.starts_with("^") {
//         syn_error!(input, "expected a regular expression starting with `^`, because it always needs to match the beginning of the remaining input");
//     }
//     let regex = match Regex::new(&regex) {
//         Err(e) => {
//             syn_error!(input, e.to_string());
//         },
//         Ok(x) => x
//     };
//     if regex.find("").is_some() {
//         syn_error!(input, "the rule regular expression must not match the empty string");
//     }
//     Ok(quote! { #input })
// }
//
//