partiql_parser/
lib.rs

1#![deny(rust_2018_idioms)]
2#![deny(clippy::all)]
3// Copyright Amazon.com, Inc. or its affiliates.
4
5//! Provides a parser for the [PartiQL][partiql] query language.
6//!
7//! # Usage
8//!
9//! ```
10//! use std::fmt;
11//! use std::fmt::Formatter;
12//! use itertools::Itertools;
13//! use partiql_common::syntax::location::LineAndColumn;
14//! use partiql_parser::{Parser, ParserError, ParserResult};
15//!
16//! let parser = Parser::default();
17//!
18//! let parsed = parser.parse("SELECT g FROM data GROUP BY a").expect("successful parse");
19//!
20//! let errs: ParserError = parser.parse("SELECT").expect_err("expected error");
21//!
22//! // Print out messages with byte offsets
23//! let errs_at: ParserError =
24//!     parser.parse("SELECT * FROM a AY a CROSS JOIN c AS c AT q").unwrap_err();
25//! assert_eq!(errs_at.errors[0].to_string(), "Unexpected token `<a:UNQUOTED_IDENT>` at `(b19..b20)`");
26//!
27//! // Print out messages with line:column offsets
28//! let errs_at_nice: ParserError =
29//!     parser.parse("SELECT * FROM a AY a CROSS JOIN c AS c AT q").unwrap_err();
30//! let offsets = &errs_at_nice.offsets;
31//! let source = &errs_at_nice.text;
32//! let err_msg = errs_at_nice.errors.iter().map(|e|
33//!     e.clone().map_loc(|loc| LineAndColumn::from(offsets.at(source, loc).unwrap()).to_string())).join("\n");
34//! assert_eq!(err_msg, "Unexpected token `<a:UNQUOTED_IDENT>` at `(1:20..1:21)`");
35//!
36//!
37//!
38//! // Print out messages with custom line:column offsets
39//! #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
40//! pub struct VerboseLineAndColumn(LineAndColumn);
41//!
42//! impl fmt::Display for VerboseLineAndColumn {
43//!     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
44//!         write!(f, "Line {}, Offset {}", self.0.line, self.0.column)
45//!     }
46//! }
47//!
48//! let err_msg = errs_at_nice.errors.iter().map(|e|
49//!     e.clone().map_loc(|loc| VerboseLineAndColumn(LineAndColumn::from(offsets.at(source, loc).unwrap())).to_string())).join("\n");
50//! assert_eq!(err_msg, "Unexpected token `<a:UNQUOTED_IDENT>` at `(Line 1, Offset 20..Line 1, Offset 21)`");
51//! ```
52//!
53//! [partiql]: https://partiql.org
54
55mod error;
56mod lexer;
57mod parse;
58mod preprocessor;
59mod token_parser;
60
61use parse::{parse_partiql, AstData, ErrorData};
62use partiql_ast::ast;
63use partiql_common::syntax::line_offset_tracker::LineOffsetTracker;
64use partiql_common::syntax::location::BytePosition;
65use partiql_common::syntax::metadata::LocationMap;
66#[cfg(feature = "serde")]
67use serde::{Deserialize, Serialize};
68
69/// [`std::error::Error`] type for errors in the lexical structure for the `PartiQL` parser.
70pub type LexicalError<'input> = error::LexError<'input>;
71
72/// [`std::error::Error`] type for errors in the syntactic structure for the `PartiQL` parser.
73pub type ParseError<'input> = error::ParseError<'input, BytePosition>;
74
75/// General [`Result`] type for the `PartiQL` [`Parser`].
76pub type ParserResult<'input> = Result<Parsed<'input>, ParserError<'input>>;
77
78/// A `PartiQL` parser from statement strings to AST.
79#[non_exhaustive]
80#[derive(Debug, Default)]
81pub struct Parser {}
82
83impl Parser {
84    /// Parse a `PartiQL` statement into an AST.
85    pub fn parse<'input>(&self, text: &'input str) -> ParserResult<'input> {
86        match parse_partiql(text) {
87            Ok(AstData {
88                ast,
89                locations,
90                offsets,
91            }) => Ok(Parsed {
92                text,
93                offsets,
94                ast,
95                locations,
96            }),
97            Err(ErrorData { errors, offsets }) => Err(ParserError {
98                text,
99                offsets,
100                errors,
101            }),
102        }
103    }
104}
105
106/// The output of parsing `PartiQL` statement strings: an AST and auxiliary data.
107#[non_exhaustive]
108#[derive(Debug)]
109#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
110#[allow(dead_code)]
111pub struct Parsed<'input> {
112    pub text: &'input str,
113    pub offsets: LineOffsetTracker,
114    pub ast: ast::AstNode<ast::TopLevelQuery>,
115    pub locations: LocationMap,
116}
117
118/// The output of errors when parsing `PartiQL` statement strings: an errors and auxiliary data.
119#[non_exhaustive]
120#[allow(dead_code)]
121#[derive(Debug)]
122#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
123pub struct ParserError<'input> {
124    pub text: &'input str,
125    pub offsets: LineOffsetTracker,
126    pub errors: Vec<ParseError<'input>>,
127}