Skip to content

Commit 730b657

Browse files
committed
Simplify lambda exp parsing
1 parent 6f9b80b commit 730b657

4 files changed

Lines changed: 35 additions & 70 deletions

File tree

src/ast/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,7 @@ pub struct LambdaFunctionParameter {
14561456
/// The name of the parameter
14571457
pub name: Ident,
14581458
/// The optional data type of the parameter
1459+
/// [Snowflake Syntax](https://docs.snowflake.com/en/sql-reference/functions/filter#arguments)
14591460
pub data_type: Option<DataType>,
14601461
}
14611462

src/parser/mod.rs

Lines changed: 28 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,43 +1559,6 @@ impl<'a> Parser<'a> {
15591559
Keyword::LAMBDA if self.dialect.supports_lambda_functions() => {
15601560
Ok(Some(self.parse_lambda_expr()?))
15611561
}
1562-
Keyword::FILTER
1563-
| Keyword::TRANSFORM
1564-
| Keyword::REDUCE if self.dialect.supports_lambda_functions() => {
1565-
self.expect_token(&Token::LParen)?;
1566-
let array = self.parse_expr()?;
1567-
self.expect_token(&Token::Comma)?;
1568-
let initial_value = if w.keyword == Keyword::REDUCE {
1569-
let initial_value = self.parse_expr()?;
1570-
self.expect_token(&Token::Comma)?;
1571-
Some(initial_value)
1572-
} else {
1573-
None
1574-
};
1575-
let lambda = self.parse_lambda_expr_with_typed_args()?;
1576-
let mut args = vec![
1577-
FunctionArg::Unnamed(FunctionArgExpr::Expr(array)),
1578-
FunctionArg::Unnamed(FunctionArgExpr::Expr(lambda)),
1579-
];
1580-
if let Some(initial_value) = initial_value {
1581-
args.insert(1, FunctionArg::Unnamed(FunctionArgExpr::Expr(initial_value)));
1582-
}
1583-
self.expect_token(&Token::RParen)?;
1584-
Ok(Some(Expr::Function(Function {
1585-
name: ObjectName::from(vec![w.to_ident(w_span)]),
1586-
uses_odbc_syntax: false,
1587-
parameters: FunctionArguments::None,
1588-
args: FunctionArguments::List(FunctionArgumentList {
1589-
duplicate_treatment: None,
1590-
clauses: vec![],
1591-
args,
1592-
}),
1593-
filter: None,
1594-
null_treatment: None,
1595-
over: None,
1596-
within_group: vec![],
1597-
})))
1598-
}
15991562
_ if self.dialect.supports_geometric_types() => match w.keyword {
16001563
Keyword::CIRCLE => Ok(Some(self.parse_geometric_type(GeometricTypeKind::Circle)?)),
16011564
Keyword::BOX => Ok(Some(self.parse_geometric_type(GeometricTypeKind::GeometricBox)?)),
@@ -1643,6 +1606,9 @@ impl<'a> Parser<'a> {
16431606
value: self.parse_introduced_string_expr()?.into(),
16441607
})
16451608
}
1609+
// An unreserved word (likely an identifier) is followed by an arrow,
1610+
// which indicates a lambda function with a single, untyped parameter.
1611+
// For example: `a -> a * 2`.
16461612
Token::Arrow if self.dialect.supports_lambda_functions() => {
16471613
self.expect_token(&Token::Arrow)?;
16481614
Ok(Expr::Lambda(LambdaFunction {
@@ -1654,6 +1620,24 @@ impl<'a> Parser<'a> {
16541620
syntax: LambdaSyntax::Arrow,
16551621
}))
16561622
}
1623+
// An unreserved word (likely an identifier) that is followed by another word (likley a data type)
1624+
// which is then followed by an arrow, which indicates a lambda function with a single, typed parameter.
1625+
// For example: `a INT -> a * 2`.
1626+
Token::Word(_)
1627+
if self.peek_nth_token_ref(1).token == Token::Arrow
1628+
&& self.dialect.supports_lambda_functions() =>
1629+
{
1630+
let data_type = self.parse_data_type()?;
1631+
self.expect_token(&Token::Arrow)?;
1632+
Ok(Expr::Lambda(LambdaFunction {
1633+
params: OneOrManyWithParens::One(LambdaFunctionParameter {
1634+
name: w.to_ident(w_span),
1635+
data_type: Some(data_type),
1636+
}),
1637+
body: Box::new(self.parse_expr()?),
1638+
syntax: LambdaSyntax::Arrow,
1639+
}))
1640+
}
16571641
_ => Ok(Expr::Identifier(w.to_ident(w_span))),
16581642
}
16591643
}
@@ -2235,7 +2219,7 @@ impl<'a> Parser<'a> {
22352219
return Ok(None);
22362220
}
22372221
self.maybe_parse(|p| {
2238-
let params = p.parse_comma_separated(|p| p.parse_lambda_function_parameter(false))?;
2222+
let params = p.parse_comma_separated(|p| p.parse_lambda_function_parameter())?;
22392223
p.expect_token(&Token::RParen)?;
22402224
p.expect_token(&Token::Arrow)?;
22412225
let expr = p.parse_expr()?;
@@ -2247,19 +2231,7 @@ impl<'a> Parser<'a> {
22472231
})
22482232
}
22492233

2250-
/// Parses a lambda expression using the arrow syntax with optionally typed arguments.
2251-
fn parse_lambda_expr_with_typed_args(&mut self) -> Result<Expr, ParserError> {
2252-
let params = self.parse_lambda_function_parameters(true)?;
2253-
self.expect_token(&Token::Arrow)?;
2254-
let body = self.parse_expr()?;
2255-
Ok(Expr::Lambda(LambdaFunction {
2256-
params,
2257-
body: Box::new(body),
2258-
syntax: LambdaSyntax::Arrow,
2259-
}))
2260-
}
2261-
2262-
/// Parses a lambda expression using the `LAMBDA` keyword syntax.
2234+
/// Parses a lambda expression following the `LAMBDA` keyword syntax.
22632235
///
22642236
/// Syntax: `LAMBDA <params> : <expr>`
22652237
///
@@ -2270,7 +2242,7 @@ impl<'a> Parser<'a> {
22702242
/// See <https://duckdb.org/docs/stable/sql/functions/lambda>
22712243
fn parse_lambda_expr(&mut self) -> Result<Expr, ParserError> {
22722244
// Parse the parameters: either a single identifier or comma-separated identifiers
2273-
let params = self.parse_lambda_function_parameters(false)?;
2245+
let params = self.parse_lambda_function_parameters()?;
22742246
// Expect the colon separator
22752247
self.expect_token(&Token::Colon)?;
22762248
// Parse the body expression
@@ -2285,19 +2257,16 @@ impl<'a> Parser<'a> {
22852257
/// Parses the parameters of a lambda function with optional typing.
22862258
fn parse_lambda_function_parameters(
22872259
&mut self,
2288-
typed: bool,
22892260
) -> Result<OneOrManyWithParens<LambdaFunctionParameter>, ParserError> {
22902261
// Parse the parameters: either a single identifier or comma-separated identifiers
22912262
let params = if self.consume_token(&Token::LParen) {
22922263
// Parenthesized parameters: (x, y)
2293-
let params =
2294-
self.parse_comma_separated(|p| p.parse_lambda_function_parameter(typed))?;
2264+
let params = self.parse_comma_separated(|p| p.parse_lambda_function_parameter())?;
22952265
self.expect_token(&Token::RParen)?;
22962266
OneOrManyWithParens::Many(params)
22972267
} else {
22982268
// Unparenthesized parameters: x or x, y
2299-
let params =
2300-
self.parse_comma_separated(|p| p.parse_lambda_function_parameter(typed))?;
2269+
let params = self.parse_comma_separated(|p| p.parse_lambda_function_parameter())?;
23012270
if params.len() == 1 {
23022271
OneOrManyWithParens::One(params.into_iter().next().unwrap())
23032272
} else {
@@ -2308,13 +2277,10 @@ impl<'a> Parser<'a> {
23082277
}
23092278

23102279
/// Parses a single parameter of a lambda function, with optional typing.
2311-
fn parse_lambda_function_parameter(
2312-
&mut self,
2313-
typed: bool,
2314-
) -> Result<LambdaFunctionParameter, ParserError> {
2280+
fn parse_lambda_function_parameter(&mut self) -> Result<LambdaFunctionParameter, ParserError> {
23152281
let name = self.parse_identifier()?;
23162282
let data_type = match self.peek_token().token {
2317-
Token::Word(_) if typed => self.maybe_parse(|p| p.parse_data_type())?,
2283+
Token::Word(_) => self.maybe_parse(|p| p.parse_data_type())?,
23182284
_ => None,
23192285
};
23202286
Ok(LambdaFunctionParameter { name, data_type })

tests/sqlparser_common.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15979,6 +15979,12 @@ fn test_lambdas() {
1597915979
"map_zip_with(map(1, 'a', 2, 'b'), map(1, 'x', 2, 'y'), (k, v1, v2) -> concat(v1, v2))",
1598015980
);
1598115981
dialects.verified_expr("transform(array(1, 2, 3), x -> x + 1)");
15982+
15983+
// Ensure all lambda variants are parsed correctly
15984+
dialects.verified_expr("a -> a * 2"); // Single parameter without type
15985+
dialects.verified_expr("a INT -> a * 2"); // Single parameter with type
15986+
dialects.verified_expr("(a, b) -> a * b"); // Multiple parameters without types
15987+
dialects.verified_expr("(a INT, b FLOAT) -> a * b"); // Multiple parameters with types
1598215988
}
1598315989

1598415990
#[test]

tests/sqlparser_snowflake.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4878,11 +4878,3 @@ fn test_truncate_table_if_exists() {
48784878
snowflake().verified_stmt("TRUNCATE TABLE my_table");
48794879
snowflake().verified_stmt("TRUNCATE IF EXISTS my_table");
48804880
}
4881-
4882-
#[test]
4883-
fn test_snowflake_lambda() {
4884-
snowflake().verified_expr("TRANSFORM([1, 2, 3], a -> a * 2)");
4885-
snowflake().verified_expr("TRANSFORM([1, 2, 3], a INT -> a * 2)");
4886-
snowflake().verified_expr("TRANSFORM([1, 2, 3], (x INT, y INT) -> (x + y))");
4887-
snowflake().verified_expr("REDUCE([1, 2, 3], 0, (acc, val) -> acc + val)");
4888-
}

0 commit comments

Comments
 (0)