Skip to main content

sql_fun_sqlast/
syn.rs

1#![doc = include_str!("syn.md")]
2
3mod generated;
4mod syn_ext;
5
6use itertools::Itertools;
7use sql_fun_core::IVec;
8
9use crate::StringSpan;
10
11pub use self::{
12    generated::*,
13    syn_ext::{ListOpt, Opt},
14};
15
16impl ScanToken {
17    /// return true when self is identifiter
18    pub fn is_ident(&self) -> bool {
19        if let Some(tok) = self.get_token().as_inner() {
20            matches!(tok, crate::syn::Token::Ident)
21        } else {
22            false
23        }
24    }
25
26    /// Return true when self is '.'
27    pub fn is_dot(&self) -> bool {
28        if let Some(tok) = self.get_token().as_inner() {
29            matches!(tok, crate::syn::Token::Ascii46)
30        } else {
31            false
32        }
33    }
34
35    /// Return true when self is comment
36    pub fn is_comment(&self) -> bool {
37        if let Some(tok) = self.get_token().as_inner() {
38            matches!(tok, crate::syn::Token::Comment)
39        } else {
40            false
41        }
42    }
43}
44
45impl TypeName {
46    /// convert `TypeName` to `full_name` string
47    #[must_use]
48    pub fn full_name(&self) -> std::string::String {
49        let Some(names) = self.get_names().as_inner() else {
50            return std::string::String::from("");
51        };
52        names
53            .iter()
54            .filter_map(|v| v.as_string().get_sval())
55            .join(".")
56    }
57
58    /// get type span
59    pub fn get_name_span(&self, tokens: &IVec<ScanToken>) -> StringSpan {
60        let location = self.get_location();
61        if location <= 0 {
62            panic!("invalid location {self:?}")
63        }
64        identifier_many_dot_identifier(tokens, location)
65    }
66}
67
68/// get span for identifier *( dot identifier )
69fn identifier_many_dot_identifier(tokens: &IVec<ScanToken>, location: i32) -> StringSpan {
70    let (start_token_index, tok) = tokens
71        .iter()
72        .find_position(|t| t.get_start() == location)
73        .unwrap();
74    let mut result_span = StringSpan::from_scan_token(tok);
75    let names_token = &mut tokens.as_slice()[start_token_index..].iter();
76    let mut expect_ident = true;
77    for tok in names_token {
78        if tok.is_comment() {
79            continue;
80        }
81        if expect_ident {
82            if tok.is_ident() {
83                result_span.extend(&StringSpan::from_scan_token(tok));
84                expect_ident = false;
85                continue;
86            } else {
87                break;
88            }
89        } else if tok.is_dot() {
90            result_span.extend(&StringSpan::from_scan_token(tok));
91            expect_ident = true;
92            continue;
93        } else {
94            break;
95        }
96    }
97    result_span
98}
99
100impl FuncCall {
101    /// get `funcname` span
102    pub fn get_funcname_span(&self, tokens: &IVec<ScanToken>) -> StringSpan {
103        let location = self.get_location();
104        if location <= 0 {
105            panic!("invalid location {self:?}")
106        }
107        identifier_many_dot_identifier(tokens, location)
108    }
109}