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::ops::Range;
16use std::ops::RangeFrom;
17use std::ops::RangeFull;
18use std::ops::RangeTo;
19
20use enum_as_inner::EnumAsInner;
21
22use crate::parser::token::Token;
23use crate::parser::Backtrace;
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 nom::InputLength for Input<'_> {
44    fn input_len(&self) -> usize {
45        self.tokens.input_len()
46    }
47}
48
49impl nom::Offset for Input<'_> {
50    fn offset(&self, second: &Self) -> usize {
51        let fst = self.tokens.as_ptr();
52        let snd = second.tokens.as_ptr();
53
54        (snd as usize - fst as usize) / std::mem::size_of::<Token>()
55    }
56}
57
58impl nom::Slice<Range<usize>> for Input<'_> {
59    fn slice(&self, range: Range<usize>) -> Self {
60        Input {
61            tokens: &self.tokens[range],
62            ..*self
63        }
64    }
65}
66
67impl nom::Slice<RangeTo<usize>> for Input<'_> {
68    fn slice(&self, range: RangeTo<usize>) -> Self {
69        Input {
70            tokens: &self.tokens[range],
71            ..*self
72        }
73    }
74}
75
76impl nom::Slice<RangeFrom<usize>> for Input<'_> {
77    fn slice(&self, range: RangeFrom<usize>) -> Self {
78        Input {
79            tokens: &self.tokens[range],
80            ..*self
81        }
82    }
83}
84
85impl nom::Slice<RangeFull> for Input<'_> {
86    fn slice(&self, _: RangeFull) -> Self {
87        *self
88    }
89}
90
91#[derive(Clone, Debug)]
92pub struct WithSpan<'a, T> {
93    pub(crate) span: Input<'a>,
94    pub(crate) elem: T,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, EnumAsInner)]
98pub enum ParseMode {
99    #[default]
100    Default,
101    Template,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, EnumAsInner)]
105pub enum Dialect {
106    #[default]
107    PostgreSQL,
108    MySQL,
109    Hive,
110    PRQL,
111    Experimental,
112}
113
114impl Dialect {
115    pub fn is_ident_quote(&self, c: char) -> bool {
116        match self {
117            Dialect::MySQL => c == '`',
118            Dialect::Hive => c == '`',
119            // TODO: remove '`' quote support once mysql handler correctly set mysql dialect.
120            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => c == '"' || c == '`',
121        }
122    }
123
124    pub fn is_string_quote(&self, c: char) -> bool {
125        match self {
126            Dialect::MySQL => c == '\'' || c == '"',
127            Dialect::Hive => c == '\'' || c == '"',
128            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => c == '\'',
129        }
130    }
131
132    pub fn substr_index_zero_literal_as_one(&self) -> bool {
133        match self {
134            Dialect::MySQL => false,
135            Dialect::Hive => true,
136            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => false,
137        }
138    }
139
140    pub fn default_ident_quote(&self) -> char {
141        match self {
142            Dialect::MySQL | Dialect::Hive => '`',
143            Dialect::Experimental | Dialect::PostgreSQL | Dialect::PRQL => '"',
144        }
145    }
146}