Skip to content

Commit d977eaa

Browse files
committed
Hide rowan behind a non-default cst feature
1 parent 8f6b0d8 commit d977eaa

File tree

6 files changed

+71
-26
lines changed

6 files changed

+71
-26
lines changed

Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ edition = "2018"
1818
name = "sqlparser"
1919
path = "src/lib.rs"
2020

21+
[features]
22+
cst = ["rowan"] # Retain a concrete synatax tree, available as `parser.syntax()`
23+
2124
[dependencies]
2225
bigdecimal = { version = "0.1.0", optional = true }
2326
log = "0.4.5"
24-
rowan = "0.10.0"
27+
rowan = { version = "0.10.0", optional = true }
2528

2629
[dev-dependencies]
2730
simple_logger = "1.0.1"

examples/cli.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,20 @@ fn main() {
5858

5959
match parse_result {
6060
Ok(statements) => {
61-
println!(
62-
"Round-trip:\n'{}'",
63-
statements
64-
.iter()
65-
.map(std::string::ToString::to_string)
66-
.collect::<Vec<_>>()
67-
.join("\n")
68-
);
69-
println!("Parse results:\n{:#?}", statements);
70-
71-
println!("Parse tree:\n{:#?}", parser.syntax());
61+
if cfg!(not(feature = "cst")) {
62+
println!(
63+
"Round-trip:\n'{}'",
64+
statements
65+
.iter()
66+
.map(std::string::ToString::to_string)
67+
.collect::<Vec<_>>()
68+
.join("\n")
69+
);
70+
println!("Parse results:\n{:#?}", statements);
71+
} else {
72+
#[cfg(feature = "cst")]
73+
println!("Parse tree:\n{:#?}", parser.syntax());
74+
}
7275
}
7376
Err(e) => {
7477
println!("Error during parsing: {:?}", e);

src/cst.rs

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ impl Token {
120120
}
121121
}
122122

123+
#[cfg(feature = "cst")]
123124
impl From<SyntaxKind> for rowan::SyntaxKind {
124125
fn from(kind: SyntaxKind) -> Self {
125126
Self(kind as u16)
@@ -128,6 +129,7 @@ impl From<SyntaxKind> for rowan::SyntaxKind {
128129

129130
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
130131
pub enum Lang {}
132+
#[cfg(feature = "cst")]
131133
impl rowan::Language for Lang {
132134
type Kind = SyntaxKind;
133135
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
@@ -139,4 +141,5 @@ impl rowan::Language for Lang {
139141
}
140142
}
141143

144+
#[cfg(feature = "cst")]
142145
pub type SyntaxNode = rowan::SyntaxNode<Lang>;

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#![warn(clippy::all)]
3636

3737
pub mod ast;
38+
#[cfg(feature = "cst")]
3839
mod builder;
3940
pub mod cst;
4041
pub mod dialect;

src/parser.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use super::tokenizer::*;
2121
use std::error::Error;
2222
use std::fmt;
2323

24+
#[cfg(feature = "cst")]
2425
use crate::builder;
26+
2527
use crate::{cst, cst::SyntaxKind as SK};
2628

2729
#[derive(Debug, Clone, PartialEq)]
@@ -41,6 +43,7 @@ macro_rules! parser_err {
4143
pub struct Marker {
4244
/// position in the token stream (`parser.index`)
4345
index: usize,
46+
#[cfg(feature = "cst")]
4447
builder_checkpoint: builder::Checkpoint,
4548
}
4649

@@ -83,13 +86,16 @@ pub struct Parser {
8386
tokens: Vec<Token>,
8487
/// The index of the first unprocessed token in `self.tokens`
8588
index: usize,
89+
90+
#[cfg(feature = "cst")]
8691
builder: builder::GreenNodeBuilder<'static>,
8792

8893
// TBD: the parser currently provides an API to move around the token
8994
// stream without restrictions (`next_token`/`prev_token`), while the
9095
// `builder` does not. To work around this, we keep a list of "pending"
9196
// tokens which have already been processed via `next_token`, but may
9297
// be put back via `prev_token`.
98+
#[cfg(feature = "cst")]
9399
pending: Vec<(cst::SyntaxKind, rowan::SmolStr)>,
94100
}
95101

@@ -112,16 +118,21 @@ macro_rules! ret {
112118
impl Parser {
113119
/// Parse the specified tokens
114120
pub fn new(tokens: Vec<Token>) -> Self {
121+
#[allow(unused_mut)]
115122
let mut parser = Parser {
116123
tokens,
117124
index: 0,
125+
#[cfg(feature = "cst")]
118126
builder: builder::GreenNodeBuilder::new(),
127+
#[cfg(feature = "cst")]
119128
pending: vec![],
120129
};
130+
#[cfg(feature = "cst")]
121131
parser.builder.start_node(SK::ROOT.into());
122132
parser
123133
}
124134

135+
#[cfg(feature = "cst")]
125136
pub fn syntax(mut self) -> cst::SyntaxNode {
126137
if self.peek_token().is_some() {
127138
// Not at end-of-file: either some extraneous tokens left after
@@ -807,6 +818,7 @@ impl Parser {
807818
self.flush_pending_buffer();
808819
Marker {
809820
index: self.index,
821+
#[cfg(feature = "cst")]
810822
builder_checkpoint: self.builder.checkpoint(),
811823
}
812824
}
@@ -826,19 +838,25 @@ impl Parser {
826838

827839
pub fn reset(&mut self, m: Marker) {
828840
self.index = m.index;
841+
#[cfg(feature = "cst")]
829842
self.pending.truncate(0);
843+
#[cfg(feature = "cst")]
830844
self.builder.reset(m.builder_checkpoint);
831845
}
832846

847+
#[allow(unused_variables)]
833848
pub fn complete<T>(&mut self, m: Marker, kind: cst::SyntaxKind, rv: T) -> T {
834849
self.flush_pending_buffer();
850+
#[cfg(feature = "cst")]
835851
self.builder
836852
.start_node_at(m.builder_checkpoint, kind.into());
853+
#[cfg(feature = "cst")]
837854
self.builder.finish_node();
838855
rv
839856
}
840857

841858
pub fn flush_pending_buffer(&mut self) {
859+
#[cfg(feature = "cst")]
842860
for (kind, s) in self.pending.drain(..) {
843861
self.builder.token(kind.into(), s);
844862
}
@@ -886,8 +904,11 @@ impl Parser {
886904
self.index += 1;
887905
#[allow(clippy::let_and_return)]
888906
let token = self.tokens.get(self.index - 1);
889-
if let Some(t) = token {
890-
self.pending.push((t.kind(), t.to_string().into()));
907+
#[cfg(feature = "cst")]
908+
{
909+
if let Some(t) = token {
910+
self.pending.push((t.kind(), t.to_string().into()));
911+
}
891912
}
892913
token
893914
}
@@ -900,10 +921,13 @@ impl Parser {
900921
assert!(self.index > 0);
901922
self.index -= 1;
902923

903-
if !self.pending.is_empty() {
904-
self.pending.pop();
905-
} else {
906-
assert!(self.index >= self.tokens.len()); // past EOF
924+
#[cfg(feature = "cst")]
925+
{
926+
if !self.pending.is_empty() {
927+
self.pending.pop();
928+
} else {
929+
assert!(self.index >= self.tokens.len()); // past EOF
930+
}
907931
}
908932

909933
if let Some(Token::Whitespace(_)) = self.tokens.get(self.index) {
@@ -913,6 +937,7 @@ impl Parser {
913937
// There may be only one non-whitespace token `pending` as by
914938
// convention, backtracking (i.e. going more than one token back)
915939
// is done via `start`/`reset` instead.
940+
#[cfg(feature = "cst")]
916941
for tok in &self.pending {
917942
assert!(tok.0 == SK::Whitespace);
918943
}
@@ -941,9 +966,12 @@ impl Parser {
941966
Some(Token::Word(ref k)) if expected.eq_ignore_ascii_case(&k.keyword) => {
942967
self.next_token();
943968
// TBD: a hack to change the "kind" of the token just processed
944-
let mut p = self.pending.pop().unwrap();
945-
p.0 = SK::KW.into();
946-
self.pending.push(p);
969+
#[cfg(feature = "cst")]
970+
{
971+
let mut p = self.pending.pop().unwrap();
972+
p.0 = SK::KW;
973+
self.pending.push(p);
974+
}
947975
true
948976
}
949977
_ => false,

src/test_utils.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,24 @@ impl TestedDialects {
5757
#[allow(clippy::let_and_return)]
5858
let rv = f(&mut parser);
5959

60-
// Concatenating CST tokens should result in a string
61-
// identical to the input SQL:
62-
let syn = parser.syntax();
63-
assert_eq!(sql, syn.to_string());
60+
#[cfg(feature = "cst")]
61+
{
62+
// Concatenating CST tokens should result in a string
63+
// identical to the input SQL:
64+
let syn = parser.syntax();
65+
assert_eq!(sql, syn.to_string());
66+
}
6467

6568
rv
6669
})
6770
}
6871

6972
pub fn parse_sql_statements(&self, sql: &str) -> Result<Vec<Statement>, ParserError> {
70-
self.run_parser_method(sql, Parser::parse_statements)
73+
if cfg!(feature = "cst") {
74+
self.run_parser_method(sql, Parser::parse_statements)
75+
} else {
76+
self.one_of_identical_results(|dialect| Parser::parse_sql(dialect, &sql))
77+
}
7178
// To fail the `ensure_multiple_dialects_are_tested` test:
7279
// Parser::parse_sql(&**self.dialects.first().unwrap(), sql)
7380
}

0 commit comments

Comments
 (0)