Skip to main content

databend_common_ast/parser/
input.rs

1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::iter::Enumerate;
16use std::ops::Bound;
17use std::ops::RangeBounds;
18
19use enum_as_inner::EnumAsInner;
20use nom::Needed;
21
22use crate::parser::Backtrace;
23use crate::parser::token::Token;
24
25/// Input tokens slice with a backtrace that records all errors including
26/// the optional branch.
27#[derive(Debug, Clone, Copy)]
28pub struct Input<'a> {
29    pub tokens: &'a [Token<'a>],
30    pub dialect: Dialect,
31    pub mode: ParseMode,
32    pub backtrace: &'a Backtrace,
33}
34
35impl<'a> std::ops::Deref for Input<'a> {
36    type Target = [Token<'a>];
37
38    fn deref(&self) -> &Self::Target {
39        self.tokens
40    }
41}
42
43impl<'a> Input<'a> {
44    pub fn slice<R>(&self, range: R) -> Self
45    where R: RangeBounds<usize> {
46        let len = self.tokens.len();
47        let start = match range.start_bound() {
48            Bound::Included(&idx) => idx,
49            Bound::Excluded(&idx) => idx + 1,
50            Bound::Unbounded => 0,
51        };
52        let end = match range.end_bound() {
53            Bound::Included(&idx) => idx + 1,
54            Bound::Excluded(&idx) => idx,
55            Bound::Unbounded => len,
56        };
57
58        Input {
59            tokens: &self.tokens[start.min(len)..end.min(len)],
60            ..*self
61        }
62    }
63}
64
65impl nom::Offset for Input<'_> {
66    fn offset(&self, second: &Self) -> usize {
67        let fst = self.tokens.as_ptr();
68        let snd = second.tokens.as_ptr();
69
70        (snd as usize - fst as usize) / std::mem::size_of::<Token>()
71    }
72}
73
74impl<'a> nom::Input for Input<'a> {
75    type Item = &'a Token<'a>;
76    type Iter = std::slice::Iter<'a, Token<'a>>;
77    type IterIndices = Enumerate<Self::Iter>;
78
79    fn input_len(&self) -> usize {
80        self.tokens.len()
81    }
82
83    fn take(&self, index: usize) -> Self {
84        self.slice(0..index)
85    }
86
87    fn take_from(&self, index: usize) -> Self {
88        self.slice(index..)
89    }
90
91    fn take_split(&self, index: usize) -> (Self, Self) {
92        let (prefix, suffix) = self.tokens.split_at(index);
93
94        (
95            Input {
96                tokens: prefix,
97                ..*self
98            },
99            Input {
100                tokens: suffix,
101                ..*self
102            },
103        )
104    }
105
106    fn position<P>(&self, predicate: P) -> Option<usize>
107    where P: Fn(Self::Item) -> bool {
108        self.tokens.iter().position(predicate)
109    }
110
111    fn iter_elements(&self) -> Self::Iter {
112        self.tokens.iter()
113    }
114
115    fn iter_indices(&self) -> Self::IterIndices {
116        self.iter_elements().enumerate()
117    }
118
119    fn slice_index(&self, count: usize) -> Result<usize, Needed> {
120        if self.tokens.len() >= count {
121            Ok(count)
122        } else {
123            Err(Needed::new(count - self.tokens.len()))
124        }
125    }
126}
127
128#[derive(Clone, Debug)]
129pub struct WithSpan<'a, T> {
130    pub(crate) span: Input<'a>,
131    pub(crate) elem: T,
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, EnumAsInner)]
135pub enum ParseMode {
136    #[default]
137    Default,
138    Template,
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, EnumAsInner)]
142pub enum Dialect {
143    #[default]
144    PostgreSQL,
145    MySQL,
146    Hive,
147    PRQL,
148    Experimental,
149}
150
151impl Dialect {
152    pub fn is_ident_quote(&self, c: char) -> bool {
153        match self {
154            Dialect::MySQL => c == '`',
155            Dialect::Hive => c == '`',
156            // TODO: remove '`' quote support once mysql handler correctly set mysql dialect.
157            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => c == '"' || c == '`',
158        }
159    }
160
161    pub fn is_string_quote(&self, c: char) -> bool {
162        match self {
163            Dialect::MySQL => c == '\'' || c == '"',
164            Dialect::Hive => c == '\'' || c == '"',
165            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => c == '\'',
166        }
167    }
168
169    pub fn substr_index_zero_literal_as_one(&self) -> bool {
170        match self {
171            Dialect::MySQL => false,
172            Dialect::Hive => true,
173            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => false,
174        }
175    }
176
177    pub fn default_ident_quote(&self) -> char {
178        match self {
179            Dialect::MySQL | Dialect::Hive => '`',
180            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => '"',
181        }
182    }
183}