1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use super::context::ParseContext;
use super::helpers::check_still_complete;
use super::segments::base::{ErasedSegment, Tables};
use crate::core::config::FluffConfig;
use crate::core::errors::SQLParseError;
use crate::dialects::ansi::FileSegment;

/// Instantiates parsed queries from a sequence of lexed raw segments.
pub struct Parser<'a> {
    config: &'a FluffConfig,
    root_segment: FileSegment,
}

impl<'a> Parser<'a> {
    pub fn new(config: &'a FluffConfig, _dialect: Option<String>) -> Self {
        Self { config, root_segment: FileSegment }
    }

    pub fn config(&self) -> &FluffConfig {
        self.config
    }

    pub fn parse(
        &self,
        tables: &Tables,
        segments: &[ErasedSegment],
        f_name: Option<String>,
        parse_statistics: bool,
    ) -> Result<Option<ErasedSegment>, SQLParseError> {
        if segments.is_empty() {
            // This should normally never happen because there will usually
            // be an end_of_file segment. It would probably only happen in
            // api use cases.
            return Ok(None);
        }

        // NOTE: This is the only time we use the parse context not in the
        // context of a context manager. That's because it's the initial
        // instantiation.
        let mut parse_cx = ParseContext::from_config(self.config);
        // Kick off parsing with the root segment. The BaseFileSegment has
        // a unique entry point to facilitate exaclty this. All other segments
        // will use the standard .match()/.parse() route.
        let root = self.root_segment.root_parse(
            tables,
            parse_cx.dialect().name,
            segments,
            &mut parse_cx,
            f_name,
        )?;

        // Basic Validation, that we haven't dropped anything.
        check_still_complete(segments, &[root.clone()], &[]);

        if parse_statistics {
            unimplemented!();
        }

        Ok(root.into())
    }
}

#[cfg(test)]
mod tests {
    use crate::core::config::FluffConfig;
    use crate::core::linter::linter::Linter;
    use crate::core::parser::segments::base::Tables;

    #[test]
    #[ignore]
    fn test_parser_parse_error() {
        let in_str = "SELECT ;".to_string();
        let config = FluffConfig::new(<_>::default(), None, None);
        let linter = Linter::new(config, None, None);
        let tables = Tables::default();
        let _ = linter.parse_string(&tables, &in_str, None, None, None);
    }
}