Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ast): improve experiment dialect #13923

Merged
merged 4 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/query/ast/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ pub fn display_parser_error(error: Error, source: &str) -> String {
let mut labels = vec![];

// Plain text error has the highest priority. Only display it if exists.
for kind in &inner.errors {
for kind in error.errors.iter().chain(&inner.errors) {
if let ErrorKind::Other(msg) = kind {
labels = vec![(inner.span, msg.to_string())];
break;
Expand Down
39 changes: 24 additions & 15 deletions src/query/ast/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
// python style list comprehensions
// python: [i for i in range(10) if i%2==0 ]
// sql: [i for i in range(10) if i%2 = 0 ]
let list_comprehensions = check_experimental_chain_function(
let list_comprehensions = check_experimental_list_comprehension(
true,
map(
rule! {
Expand Down Expand Up @@ -1244,9 +1244,13 @@ pub fn column_id(i: Input) -> IResult<ColumnID> {
alt((
map_res(rule! { ColumnPosition }, |token| {
let name = token.text().to_string();
let pos = name[1..].parse::<usize>()?;
let pos = name[1..]
.parse::<usize>()
.map_err(|e| nom::Err::Failure(e.into()))?;
if pos == 0 {
return Err(ErrorKind::Other("column position must be greater than 0"));
return Err(nom::Err::Failure(ErrorKind::Other(
"column position must be greater than 0",
)));
}
Ok(ColumnID::Position(crate::ast::ColumnPosition {
pos,
Expand Down Expand Up @@ -1384,9 +1388,11 @@ pub fn literal_u64(i: Input) -> IResult<u64> {
rule! {
LiteralInteger
},
|token| Ok(u64::from_str_radix(token.text(), 10)?),
|token| u64::from_str_radix(token.text(), 10).map_err(|e| nom::Err::Failure(e.into())),
);
let hex = map_res(literal_hex_str, |lit| Ok(u64::from_str_radix(lit, 16)?));
let hex = map_res(literal_hex_str, |lit| {
u64::from_str_radix(lit, 16).map_err(|e| nom::Err::Failure(e.into()))
});

rule!(
#decimal
Expand All @@ -1399,16 +1405,18 @@ pub fn literal_number(i: Input) -> IResult<Literal> {
rule! {
LiteralInteger
},
|token| parse_uint(token.text(), 10),
|token| parse_uint(token.text(), 10).map_err(nom::Err::Failure),
);

let hex_uint = map_res(literal_hex_str, |str| parse_uint(str, 16));
let hex_uint = map_res(literal_hex_str, |str| {
parse_uint(str, 16).map_err(nom::Err::Failure)
});

let decimal_float = map_res(
rule! {
LiteralFloat
},
|token| parse_float(token.text()),
|token| parse_float(token.text()).map_err(nom::Err::Failure),
);

rule!(
Expand Down Expand Up @@ -1436,11 +1444,12 @@ pub fn literal_string(i: Input) -> IResult<String> {
.is_some()
{
let str = &token.text()[1..token.text().len() - 1];
let unescaped = unescape_string(str, '\'')
.ok_or(ErrorKind::Other("invalid escape or unicode"))?;
let unescaped = unescape_string(str, '\'').ok_or(nom::Err::Failure(
ErrorKind::Other("invalid escape or unicode"),
))?;
Ok(unescaped)
} else {
Err(ErrorKind::ExpectToken(QuotedString))
Err(nom::Err::Error(ErrorKind::ExpectToken(QuotedString)))
}
},
)(i)
Expand All @@ -1452,7 +1461,7 @@ pub fn literal_string_eq_ignore_case(s: &str) -> impl FnMut(Input) -> IResult<()
if token.text()[1..token.text().len() - 1].eq_ignore_ascii_case(s) {
Ok(())
} else {
Err(ErrorKind::ExpectToken(QuotedString))
Err(nom::Err::Error(ErrorKind::ExpectToken(QuotedString)))
}
})(i)
}
Expand Down Expand Up @@ -1510,11 +1519,11 @@ pub fn type_name(i: Input) -> IResult<TypeName> {
Ok(TypeName::Decimal {
precision: precision
.try_into()
.map_err(|_| ErrorKind::Other("precision is too large"))?,
.map_err(|_| nom::Err::Failure(ErrorKind::Other("precision is too large")))?,
scale: if let Some((_, scale)) = opt_scale {
scale
.try_into()
.map_err(|_| ErrorKind::Other("scale is too large"))?
.map_err(|_| nom::Err::Failure(ErrorKind::Other("scale is too large")))?
} else {
0
},
Expand Down Expand Up @@ -1677,7 +1686,7 @@ pub fn map_access(i: Input) -> IResult<MapAccessor> {
return Ok(MapAccessor::DotNumber { key });
}
}
Err(ErrorKind::ExpectText("."))
Err(nom::Err::Error(ErrorKind::ExpectText(".")))
},
);
let colon = map(
Expand Down
110 changes: 38 additions & 72 deletions src/query/ast/src/parser/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use crate::parser::statement::hint;
use crate::parser::token::*;
use crate::rule;
use crate::util::*;
use crate::ErrorKind;

pub fn query(i: Input) -> IResult<Query> {
context(
Expand All @@ -41,7 +42,7 @@ pub fn query(i: Input) -> IResult<Query> {
}

pub fn set_operation(i: Input) -> IResult<SetExpr> {
let (rest, set_operation_elements) = rule!(#set_operation_element+)(i)?;
let (rest, set_operation_elements) = rule! { #set_operation_element+ }(i)?;
let iter = &mut set_operation_elements.into_iter();
run_pratt_parser(SetOperationParser, iter, rest, i)
}
Expand All @@ -52,13 +53,13 @@ pub enum SetOperationElement {
SelectStmt {
hints: Option<Hint>,
distinct: bool,
select_list: Box<Vec<SelectTarget>>,
from: Box<Vec<TableReference>>,
selection: Box<Option<Expr>>,
select_list: Vec<SelectTarget>,
from: Vec<TableReference>,
selection: Option<Expr>,
group_by: Option<GroupBy>,
having: Box<Option<Expr>>,
having: Option<Expr>,
window_list: Option<Vec<WindowDefinition>>,
qualify: Box<Option<Expr>>,
qualify: Option<Expr>,
},
SetOperation {
op: SetOperator,
Expand Down Expand Up @@ -97,84 +98,50 @@ pub fn set_operation_element(i: Input) -> IResult<WithSpan<SetOperationElement>>
}
},
);
let select_stmt = map(
let select_stmt = map_res(
rule! {
SELECT ~ #hint? ~ DISTINCT? ~ ^#comma_separated_list1(select_target)
~ ( FROM ~ ^#comma_separated_list1(table_reference) )?
~ ( WHERE ~ ^#expr )?
~ ( GROUP ~ ^BY ~ ^#group_by_items )?
~ ( HAVING ~ ^#expr )?
~ ( WINDOW ~ ^#comma_separated_list1(window_clause) )?
~ ( QUALIFY ~ ^#expr )?
( FROM ~ ^#comma_separated_list1(table_reference) )?
~ SELECT ~ #hint? ~ DISTINCT? ~ ^#comma_separated_list1(select_target)
~ ( FROM ~ ^#comma_separated_list1(table_reference) )?
~ ( WHERE ~ ^#expr )?
~ ( GROUP ~ ^BY ~ ^#group_by_items )?
~ ( HAVING ~ ^#expr )?
~ ( WINDOW ~ ^#comma_separated_list1(window_clause) )?
~ ( QUALIFY ~ ^#expr )?
},
|(
opt_from_block_first,
_select,
opt_hints,
opt_distinct,
select_list,
opt_from_block,
opt_from_block_second,
opt_where_block,
opt_group_by_block,
opt_having_block,
opt_window_block,
opt_qualify_block,
)| {
SetOperationElement::SelectStmt {
hints: opt_hints,
distinct: opt_distinct.is_some(),
select_list: Box::new(select_list),
from: Box::new(
opt_from_block
.map(|(_, table_refs)| table_refs)
.unwrap_or_default(),
),
selection: Box::new(opt_where_block.map(|(_, selection)| selection)),
group_by: opt_group_by_block.map(|(_, _, group_by)| group_by),
having: Box::new(opt_having_block.map(|(_, having)| having)),
window_list: opt_window_block.map(|(_, windows)| windows),
qualify: Box::new(opt_qualify_block.map(|(_, qualify)| qualify)),
if opt_from_block_first.is_some() && opt_from_block_second.is_some() {
return Err(nom::Err::Failure(ErrorKind::Other(
"duplicated FROM clause",
)));
}
},
);

// From ... Select
let select_stmt_from_first = map(
rule! {
( FROM ~ ^#comma_separated_list1(table_reference) )?
~ SELECT ~ #hint? ~ DISTINCT? ~ ^#comma_separated_list1(select_target)
~ ( WHERE ~ ^#expr )?
~ ( GROUP ~ ^BY ~ ^#group_by_items )?
~ ( HAVING ~ ^#expr )?
~ ( WINDOW ~ ^#comma_separated_list1(window_clause) )?
~ ( QUALIFY ~ ^#expr )?
},
|(
opt_from_block,
_select,
opt_hints,
opt_distinct,
select_list,
opt_where_block,
opt_group_by_block,
opt_having_block,
opt_window_block,
opt_qualify_block,
)| {
SetOperationElement::SelectStmt {
Ok(SetOperationElement::SelectStmt {
hints: opt_hints,
distinct: opt_distinct.is_some(),
select_list: Box::new(select_list),
from: Box::new(
opt_from_block
.map(|(_, table_refs)| table_refs)
.unwrap_or_default(),
),
selection: Box::new(opt_where_block.map(|(_, selection)| selection)),
select_list,
from: opt_from_block_first
.or(opt_from_block_second)
.map(|(_, table_refs)| table_refs)
.unwrap_or_default(),
selection: opt_where_block.map(|(_, selection)| selection),
group_by: opt_group_by_block.map(|(_, _, group_by)| group_by),
having: Box::new(opt_having_block.map(|(_, having)| having)),
having: opt_having_block.map(|(_, having)| having),
window_list: opt_window_block.map(|(_, windows)| windows),
qualify: Box::new(opt_qualify_block.map(|(_, qualify)| qualify)),
}
qualify: opt_qualify_block.map(|(_, qualify)| qualify),
})
},
);

Expand Down Expand Up @@ -220,7 +187,6 @@ pub fn set_operation_element(i: Input) -> IResult<WithSpan<SetOperationElement>>
| #with
| #set_operator
| #select_stmt
| #select_stmt_from_first
| #values
| #order_by
| #limit
Expand Down Expand Up @@ -274,13 +240,13 @@ impl<'a, I: Iterator<Item = WithSpan<'a, SetOperationElement>>> PrattParser<I>
span: transform_span(input.span.0),
hints,
distinct,
select_list: *select_list,
from: *from,
selection: *selection,
select_list,
from,
selection,
group_by,
having: *having,
having,
window_list,
qualify: *qualify,
qualify,
})),
SetOperationElement::Values(values) => SetExpr::Values {
span: transform_span(input.span.0),
Expand Down Expand Up @@ -626,7 +592,7 @@ pub fn order_by_expr(i: Input) -> IResult<OrderByExpr> {
}

pub fn table_reference(i: Input) -> IResult<TableReference> {
let (rest, table_reference_elements) = rule!(#table_reference_element+)(i)?;
let (rest, table_reference_elements) = rule! { #table_reference_element+ }(i)?;
let iter = &mut table_reference_elements.into_iter();
run_pratt_parser(TableReferenceParser, iter, rest, i)
}
Expand Down
2 changes: 1 addition & 1 deletion src/query/ast/src/parser/share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn share_endpoint_uri_location(i: Input) -> IResult<UriLocation> {
},
|location| {
UriLocation::from_uri(location, "".to_string(), BTreeMap::new())
.map_err(|_| ErrorKind::Other("invalid uri"))
.map_err(|_| nom::Err::Failure(ErrorKind::Other("invalid uri")))
},
)(i)
}
14 changes: 10 additions & 4 deletions src/query/ast/src/parser/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,17 @@ pub fn file_location(i: Input) -> IResult<FileLocation> {
pub fn stage_location(i: Input) -> IResult<String> {
map_res(file_location, |location| match location {
FileLocation::Stage(s) => Ok(s),
FileLocation::Uri(_) => Err(ErrorKind::Other("expect stage location, got uri location")),
FileLocation::Uri(_) => Err(nom::Err::Failure(ErrorKind::Other(
"expect stage location, got uri location",
))),
})(i)
}

pub fn uri_location(i: Input) -> IResult<UriLocation> {
map_res(string_location, |location| match location {
FileLocation::Stage(_) => Err(ErrorKind::Other("uri location should not start with '@'")),
FileLocation::Stage(_) => Err(nom::Err::Failure(ErrorKind::Other(
"uri location should not start with '@'",
))),
FileLocation::Uri(u) => Ok(u),
})(i)
}
Expand All @@ -192,7 +196,9 @@ pub fn string_location(i: Input) -> IResult<FileLocation> {
{
Ok(FileLocation::Stage(stripped.to_string()))
} else {
Err(ErrorKind::Other("uri location should not start with '@'"))
Err(nom::Err::Failure(ErrorKind::Other(
"uri location should not start with '@'",
)))
}
} else {
let part_prefix = if let Some((_, _, p, _)) = location_prefix {
Expand All @@ -207,7 +213,7 @@ pub fn string_location(i: Input) -> IResult<FileLocation> {
conns.extend(credentials_opts.map(|v| v.2).unwrap_or_default());

let uri = UriLocation::from_uri(location, part_prefix, conns)
.map_err(|_| ErrorKind::Other("invalid uri"))?;
.map_err(|_| nom::Err::Failure(ErrorKind::Other("invalid uri")))?;
Ok(FileLocation::Uri(uri))
}
},
Expand Down
12 changes: 8 additions & 4 deletions src/query/ast/src/parser/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,17 @@ pub fn statement(i: Input) -> IResult<StatementWithFormat> {
Ok(Statement::Explain {
kind: match opt_kind.map(|token| token.kind) {
Some(TokenKind::AST) => {
let formatted_stmt = format_statement(statement.stmt.clone())
.map_err(|_| ErrorKind::Other("invalid statement"))?;
let formatted_stmt =
format_statement(statement.stmt.clone()).map_err(|_| {
nom::Err::Failure(ErrorKind::Other("invalid statement"))
})?;
ExplainKind::Ast(formatted_stmt)
}
Some(TokenKind::SYNTAX) => {
let pretty_stmt = pretty_statement(statement.stmt.clone(), 10)
.map_err(|_| ErrorKind::Other("invalid statement"))?;
let pretty_stmt =
pretty_statement(statement.stmt.clone(), 10).map_err(|_| {
nom::Err::Failure(ErrorKind::Other("invalid statement"))
})?;
ExplainKind::Syntax(pretty_stmt)
}
Some(TokenKind::PIPELINE) => ExplainKind::Pipeline,
Expand Down
7 changes: 5 additions & 2 deletions src/query/ast/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,16 @@ pub fn map_res<'a, O1, O2, F, G>(
) -> impl FnMut(Input<'a>) -> IResult<'a, O2>
where
F: nom::Parser<Input<'a>, O1, Error<'a>>,
G: FnMut(O1) -> Result<O2, ErrorKind>,
G: FnMut(O1) -> Result<O2, nom::Err<ErrorKind>>,
{
move |input: Input| {
let i = input;
let (input, o1) = parser.parse(input)?;
match f(o1) {
Ok(o2) => Ok((input, o2)),
Err(e) => Err(nom::Err::Error(Error::from_error_kind(i, e))),
Err(nom::Err::Error(e)) => Err(nom::Err::Error(Error::from_error_kind(i, e))),
Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(Error::from_error_kind(i, e))),
Err(nom::Err::Incomplete(_)) => unimplemented!(),
}
}
}
Expand Down Expand Up @@ -443,3 +445,4 @@ macro_rules! declare_experimental_feature {
}

declare_experimental_feature!(check_experimental_chain_function, "chain function");
declare_experimental_feature!(check_experimental_list_comprehension, "list comprehension");
Loading
Loading