databend_common_ast/
span.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::fmt::Debug;
16use std::fmt::Display;
17use std::fmt::Formatter;
18
19use derive_visitor::Drive;
20use derive_visitor::DriveMut;
21use serde::Deserialize;
22use serde::Serialize;
23
24pub type Span = Option<Range>;
25
26#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Drive, DriveMut)]
27pub struct Range {
28    pub start: u32,
29    pub end: u32,
30}
31
32impl Range {
33    pub fn start(&self) -> usize {
34        self.start as usize
35    }
36
37    pub fn end(&self) -> usize {
38        self.end as usize
39    }
40}
41
42impl Debug for Range {
43    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
44        write!(f, "{}..{}", self.start, self.end)
45    }
46}
47
48impl Display for Range {
49    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
50        write!(f, "{}..{}", self.start, self.end)
51    }
52}
53
54impl From<Range> for std::ops::Range<usize> {
55    fn from(range: Range) -> std::ops::Range<usize> {
56        (range.start as usize)..(range.end as usize)
57    }
58}
59
60impl From<std::ops::Range<usize>> for Range {
61    fn from(range: std::ops::Range<usize>) -> Range {
62        Range {
63            start: range.start as u32,
64            end: range.end as u32,
65        }
66    }
67}
68
69pub fn offset_span(span: Span, offset: usize) -> Span {
70    span.map(|range| Range {
71        start: range.start + offset as u32,
72        end: range.end + offset as u32,
73    })
74}
75
76pub fn merge_span(lhs: Span, rhs: Span) -> Span {
77    match (lhs, rhs) {
78        (Some(lhs), Some(rhs)) => Some(Range {
79            start: lhs.start.min(rhs.start),
80            end: lhs.end.max(rhs.end),
81        }),
82        (Some(lhs), None) => Some(lhs),
83        (None, Some(rhs)) => Some(rhs),
84        (None, None) => None,
85    }
86}
87
88pub fn pretty_print_error(source: &str, labels: Vec<(Range, String)>) -> String {
89    use rspack_codespan_reporting::diagnostic::Diagnostic;
90    use rspack_codespan_reporting::diagnostic::Label;
91    use rspack_codespan_reporting::files::SimpleFile;
92    use rspack_codespan_reporting::term;
93    use rspack_codespan_reporting::term::termcolor::Buffer;
94    use rspack_codespan_reporting::term::Chars;
95    use rspack_codespan_reporting::term::Config;
96
97    let mut writer = Buffer::no_color();
98    let file = SimpleFile::new("SQL", source);
99    let config = Config {
100        chars: Chars::ascii(),
101        before_label_lines: 3,
102        ..Default::default()
103    };
104
105    let labels = labels
106        .into_iter()
107        .enumerate()
108        .map(|(i, (span, msg))| {
109            if i == 0 {
110                Label::primary((), span).with_message(msg)
111            } else {
112                Label::secondary((), span).with_message(msg)
113            }
114        })
115        .collect();
116
117    let diagnostic = Diagnostic::error().with_labels(labels);
118
119    term::emit(&mut writer, &config, &file, &diagnostic).unwrap();
120
121    std::str::from_utf8(&writer.into_inner())
122        .unwrap()
123        .to_string()
124}