Skip to main content

sqlparser_derive/
dialect.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Implementation of the `derive_dialect!` macro for creating custom SQL dialects.
19
20use proc_macro2::TokenStream;
21use quote::{quote, quote_spanned};
22use std::collections::HashSet;
23use syn::{
24    braced,
25    parse::{Parse, ParseStream},
26    Error, File, FnArg, Ident, Item, LitBool, LitChar, Pat, ReturnType, Signature, Token,
27    TraitItem, Type,
28};
29
30/// Override value types supported by the macro
31pub(crate) enum Override {
32    Bool(LitBool),
33    Char(LitChar),
34    None,
35}
36
37/// Parsed input for the `derive_dialect!` macro
38pub(crate) struct DeriveDialectInput {
39    pub name: Ident,
40    pub base: Type,
41    pub preserve_type_id: bool,
42    pub overrides: Vec<(Ident, Override)>,
43}
44
45/// `Dialect` trait method attrs
46struct DialectMethod {
47    name: Ident,
48    signature: Signature,
49}
50
51impl Parse for DeriveDialectInput {
52    fn parse(input: ParseStream) -> syn::Result<Self> {
53        let name: Ident = input.parse()?;
54        input.parse::<::syn::token::CommaToken![,]>()?;
55        let base: Type = input.parse()?;
56
57        let mut preserve_type_id = false;
58        let mut overrides = Vec::new();
59
60        while input.peek(::syn::token::CommaToken![,]) {
61            input.parse::<::syn::token::CommaToken![,]>()?;
62            if input.is_empty() {
63                break;
64            }
65            if input.peek(Ident) {
66                let ident: Ident = input.parse()?;
67                match ident.to_string().as_str() {
68                    "preserve_type_id" => {
69                        input.parse::<::syn::token::EqToken![=]>()?;
70                        preserve_type_id = input.parse::<LitBool>()?.value();
71                    }
72                    "overrides" => {
73                        input.parse::<::syn::token::EqToken![=]>()?;
74                        let content;
75                        match ::syn::__private::parse_braces(&input) {
    ::syn::__private::Ok(braces) => {
        content = braces.content;
        _ = content;
        braces.token
    }
    ::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};braced!(content in input);
76                        while !content.is_empty() {
77                            let key: Ident = content.parse()?;
78                            content.parse::<::syn::token::EqToken![=]>()?;
79                            let value = if content.peek(LitBool) {
80                                Override::Bool(content.parse()?)
81                            } else if content.peek(LitChar) {
82                                Override::Char(content.parse()?)
83                            } else if content.peek(Ident) {
84                                let ident: Ident = content.parse()?;
85                                if ident == "None" {
86                                    Override::None
87                                } else {
88                                    return Err(Error::new(
89                                        ident.span(),
90                                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Expected `true`, `false`, a char, or `None`, found `{0}`",
                ident))
    })format!("Expected `true`, `false`, a char, or `None`, found `{ident}`"),
91                                    ));
92                                }
93                            } else {
94                                return Err(
95                                    content.error("Expected `true`, `false`, a char, or `None`")
96                                );
97                            };
98                            overrides.push((key, value));
99                            if content.peek(::syn::token::CommaToken![,]) {
100                                content.parse::<::syn::token::CommaToken![,]>()?;
101                            }
102                        }
103                    }
104                    other => {
105                        return Err(Error::new(ident.span(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Unknown argument `{0}`. Expected `preserve_type_id` or `overrides`.",
                other))
    })format!(
106                            "Unknown argument `{other}`. Expected `preserve_type_id` or `overrides`."
107                        )));
108                    }
109                }
110            }
111        }
112        Ok(DeriveDialectInput {
113            name,
114            base,
115            preserve_type_id,
116            overrides,
117        })
118    }
119}
120
121/// Entry point for the `derive_dialect!` macro
122pub(crate) fn derive_dialect(input: DeriveDialectInput) -> proc_macro::TokenStream {
123    let err = |msg: String| {
124        Error::new(proc_macro2::Span::call_site(), msg)
125            .to_compile_error()
126            .into()
127    };
128
129    let source = match read_dialect_mod_file() {
130        Ok(s) => s,
131        Err(e) => return err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Failed to read dialect/mod.rs: {0}",
                e))
    })format!("Failed to read dialect/mod.rs: {e}")),
132    };
133    let file: File = match syn::parse_str(&source) {
134        Ok(f) => f,
135        Err(e) => return err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Failed to parse source: {0}", e))
    })format!("Failed to parse source: {e}")),
136    };
137    let methods = match extract_dialect_methods(&file) {
138        Ok(m) => m,
139        Err(e) => return e.to_compile_error().into(),
140    };
141
142    // Validate overrides
143    let bool_names: HashSet<_> = methods
144        .iter()
145        .filter(|m| is_bool_method(&m.signature))
146        .map(|m| m.name.to_string())
147        .collect();
148    for (key, value) in &input.overrides {
149        let key_str = key.to_string();
150        let err = |msg| Error::new(key.span(), msg).to_compile_error().into();
151        match value {
152            Override::Bool(_) if !bool_names.contains(&key_str) => {
153                return err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Unknown boolean method `{0}`",
                key_str))
    })format!("Unknown boolean method `{key_str}`"));
154            }
155            Override::Char(_) | Override::None if key_str != "identifier_quote_style" => {
156                return err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Char/None only valid for `identifier_quote_style`, not `{0}`",
                key_str))
    })format!(
157                    "Char/None only valid for `identifier_quote_style`, not `{key_str}`"
158                ));
159            }
160            _ => {}
161        }
162    }
163    generate_derived_dialect(&input, &methods).into()
164}
165
166/// Generate the complete derived `Dialect` implementation
167fn generate_derived_dialect(input: &DeriveDialectInput, methods: &[DialectMethod]) -> TokenStream {
168    let name = &input.name;
169    let base = &input.base;
170
171    // Helper to find an override by method name
172    let find_override = |method_name: &str| {
173        input
174            .overrides
175            .iter()
176            .find(|(k, _)| k == method_name)
177            .map(|(_, v)| v)
178    };
179
180    // Helper to generate delegation to base dialect
181    let delegate = |method: &DialectMethod| {
182        let sig = &method.signature;
183        let method_name = &method.name;
184        let params = extract_param_names(sig);
185        {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(method_name.span()).__into_span();
    ::quote::ToTokens::to_tokens(&sig, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "self");
            ::quote::__private::push_dot_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "dialect");
            ::quote::__private::push_dot_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&method_name, &mut _s);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    {
                        use ::quote::__private::ext::*;
                        let mut _first = true;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut params, i) = params.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let params =
                                match params.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            if !_first {
                                ::quote::__private::push_comma_spanned(&mut _s, _span);
                            }
                            _first = false;
                            ::quote::ToTokens::to_tokens(&params, &mut _s);
                        }
                    }
                    _s
                });
            _s
        });
    _s
}quote_spanned! { method_name.span() => #sig { self.dialect.#method_name(#(#params),*) } }
186    };
187
188    // Generate the struct
189    let struct_def = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(name.span()).__into_span();
    ::quote::__private::push_pound_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "derive");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "Debug");
                    ::quote::__private::push_comma_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "Default");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident_spanned(&mut _s, _span, "pub");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "struct");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "dialect");
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&base, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    ::quote::__private::push_ident_spanned(&mut _s, _span, "impl");
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "pub");
            ::quote::__private::push_ident_spanned(&mut _s, _span, "fn");
            ::quote::__private::push_ident_spanned(&mut _s, _span, "new");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let _: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::TokenStream::new()
                });
            ::quote::__private::push_rarrow_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Self");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _span: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "Self");
                    ::quote::__private::push_colon2_spanned(&mut _s, _span);
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "default");
                    ::quote::__private::push_group_spanned(&mut _s, _span,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let _: ::quote::__private::Span =
                                ::quote::__private::get_span(_span).__into_span();
                            ::quote::__private::TokenStream::new()
                        });
                    _s
                });
            _s
        });
    _s
}quote_spanned! { name.span() =>
190        #[derive(Debug, Default)]
191        pub struct #name {
192            dialect: #base,
193        }
194        impl #name {
195            pub fn new() -> Self { Self::default() }
196        }
197    };
198
199    // Generate TypeId method body
200    let type_id_body = if input.preserve_type_id {
201        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "Dialect");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "dialect");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_ident(&mut _s, "self");
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "dialect");
            _s
        });
    _s
}quote! { Dialect::dialect(&self.dialect) }
202    } else {
203        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "any");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "TypeId");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "of");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    _s
}quote! { ::core::any::TypeId::of::<#name>() }
204    };
205
206    // Generate method implementations
207    let method_impls = methods.iter().map(|method| {
208        let method_name = &method.name;
209        match find_override(&method_name.to_string()) {
210            Some(Override::Bool(value)) => {
211                {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(method_name.span()).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "fn");
    ::quote::ToTokens::to_tokens(&method_name, &mut _s);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "self");
            _s
        });
    ::quote::__private::push_rarrow_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "bool");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::ToTokens::to_tokens(&value, &mut _s);
            _s
        });
    _s
}quote_spanned! { method_name.span() => fn #method_name(&self) -> bool { #value } }
212            }
213            Some(Override::Char(c)) => {
214                {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(method_name.span()).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "fn");
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "identifier_quote_style");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "self");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_underscore_spanned(&mut _s, _span);
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "str");
            _s
        });
    ::quote::__private::push_rarrow_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "char");
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Some");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    let _: ::quote::__private::Span =
                        ::quote::__private::get_span(_span).__into_span();
                    ::quote::ToTokens::to_tokens(&c, &mut _s);
                    _s
                });
            _s
        });
    _s
}quote_spanned! { method_name.span() =>
215                    fn identifier_quote_style(&self, _: &str) -> Option<char> { Some(#c) }
216                }
217            }
218            Some(Override::None) => {
219                {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(method_name.span()).__into_span();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "fn");
    ::quote::__private::push_ident_spanned(&mut _s, _span,
        "identifier_quote_style");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "self");
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_underscore_spanned(&mut _s, _span);
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::__private::push_and_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span, "str");
            _s
        });
    ::quote::__private::push_rarrow_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Option");
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "char");
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            let _span: ::quote::__private::Span =
                ::quote::__private::get_span(_span).__into_span();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "None");
            _s
        });
    _s
}quote_spanned! { method_name.span() =>
220                    fn identifier_quote_style(&self, _: &str) -> Option<char> { None }
221                }
222            }
223            None => delegate(method),
224        }
225    });
226
227    // Wrap impl in a const block with scoped imports so types resolve without qualification
228    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&struct_def, &mut _s);
    ::quote::__private::push_ident(&mut _s, "const");
    ::quote::__private::push_underscore(&mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "use");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "iter");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Peekable");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "use");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "str");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Chars");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "use");
            ::quote::__private::push_ident(&mut _s, "sqlparser");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ast");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "ColumnOption");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Expr");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "GranteesType");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Ident");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "ObjectNamePart");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Statement");
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "use");
            ::quote::__private::push_ident(&mut _s, "sqlparser");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "dialect");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "Dialect");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Precedence");
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "use");
            ::quote::__private::push_ident(&mut _s, "sqlparser");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "keywords");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Keyword");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "use");
            ::quote::__private::push_ident(&mut _s, "sqlparser");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "parser");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "Parser");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "ParserError");
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "impl");
            ::quote::__private::push_ident(&mut _s, "Dialect");
            ::quote::__private::push_ident(&mut _s, "for");
            ::quote::ToTokens::to_tokens(&name, &mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "fn");
                    ::quote::__private::push_ident(&mut _s, "dialect");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_and(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "self");
                            _s
                        });
                    ::quote::__private::push_rarrow(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "core");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "any");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "TypeId");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::ToTokens::to_tokens(&type_id_body, &mut _s);
                            _s
                        });
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut method_impls, i) = method_impls.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let method_impls =
                                match method_impls.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&method_impls, &mut _s);
                        }
                    }
                    _s
                });
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
229        #struct_def
230        const _: () = {
231            use ::core::iter::Peekable;
232            use ::core::str::Chars;
233            use sqlparser::ast::{ColumnOption, Expr, GranteesType, Ident, ObjectNamePart, Statement};
234            use sqlparser::dialect::{Dialect, Precedence};
235            use sqlparser::keywords::Keyword;
236            use sqlparser::parser::{Parser, ParserError};
237
238            impl Dialect for #name {
239                fn dialect(&self) -> ::core::any::TypeId { #type_id_body }
240                #(#method_impls)*
241            }
242        };
243    }
244}
245
246/// Extract parameter names from a method signature (excluding self)
247fn extract_param_names(sig: &Signature) -> Vec<&Ident> {
248    sig.inputs
249        .iter()
250        .filter_map(|arg| match arg {
251            FnArg::Typed(pt) => match pt.pat.as_ref() {
252                Pat::Ident(pi) => Some(&pi.ident),
253                _ => None,
254            },
255            _ => None,
256        })
257        .collect()
258}
259
260/// Read the `dialect/mod.rs` file that contains the Dialect trait.
261fn read_dialect_mod_file() -> Result<String, String> {
262    let manifest_dir =
263        std::env::var("CARGO_MANIFEST_DIR").map_err(|_| "CARGO_MANIFEST_DIR not set")?;
264    let path = std::path::Path::new(&manifest_dir).join("src/dialect/mod.rs");
265    std::fs::read_to_string(&path).map_err(|e| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Failed to read {0}: {1}",
                path.display(), e))
    })format!("Failed to read {}: {e}", path.display()))
266}
267
268/// Extract all methods from the `Dialect` trait (excluding `dialect` for TypeId)
269fn extract_dialect_methods(file: &File) -> Result<Vec<DialectMethod>, Error> {
270    let dialect_trait = file
271        .items
272        .iter()
273        .find_map(|item| match item {
274            Item::Trait(t) if t.ident == "Dialect" => Some(t),
275            _ => None,
276        })
277        .ok_or_else(|| Error::new(proc_macro2::Span::call_site(), "Dialect trait not found"))?;
278
279    let mut methods: Vec<_> = dialect_trait
280        .items
281        .iter()
282        .filter_map(|item| match item {
283            TraitItem::Fn(m) if m.sig.ident != "dialect" => Some(DialectMethod {
284                name: m.sig.ident.clone(),
285                signature: m.sig.clone(),
286            }),
287            _ => None,
288        })
289        .collect();
290    methods.sort_by_key(|m| m.name.to_string());
291    Ok(methods)
292}
293
294/// Check if a method signature is `fn name(&self) -> bool`
295fn is_bool_method(sig: &Signature) -> bool {
296    sig.inputs.len() == 1
297        && #[allow(non_exhaustive_omitted_patterns)] match sig.inputs.first() {
    Some(FnArg::Receiver(r)) if
        r.reference.is_some() && r.mutability.is_none() => true,
    _ => false,
}matches!(
298            sig.inputs.first(),
299            Some(FnArg::Receiver(r)) if r.reference.is_some() && r.mutability.is_none()
300        )
301        && #[allow(non_exhaustive_omitted_patterns)] match &sig.output {
    ReturnType::Type(_, ty) if
        #[allow(non_exhaustive_omitted_patterns)] match ty.as_ref() {
            Type::Path(p) if p.path.is_ident("bool") => true,
            _ => false,
        } => true,
    _ => false,
}matches!(
302            &sig.output,
303            ReturnType::Type(_, ty) if matches!(ty.as_ref(), Type::Path(p) if p.path.is_ident("bool"))
304        )
305}