@@ -60,6 +60,7 @@ module.exports = grammar({
6060 $ . from_clause ,
6161 repeat ( choice (
6262 $ . window_function ,
63+ $ . case_expression ,
6364 $ . cast_expression ,
6465 $ . function_call ,
6566 $ . non_from_sql_keyword ,
@@ -80,6 +81,7 @@ module.exports = grammar({
8081 select_body : $ => prec . left ( repeat1 ( choice (
8182 $ . from_clause ,
8283 $ . window_function , // Window functions like ROW_NUMBER() OVER (...)
84+ $ . case_expression , // CASE WHEN ... THEN ... END
8385 $ . cast_expression , // CAST(expr AS type), TRY_CAST(expr AS type)
8486 $ . function_call , // Regular function calls like COUNT(), SUM()
8587 $ . sql_keyword ,
@@ -210,6 +212,7 @@ module.exports = grammar({
210212 // Token-by-token fallback for any other subquery content
211213 subquery_body : $ => repeat1 ( choice (
212214 $ . window_function ,
215+ $ . case_expression ,
213216 $ . cast_expression ,
214217 $ . function_call ,
215218 $ . sql_keyword ,
@@ -221,6 +224,41 @@ module.exports = grammar({
221224 token ( / [ ^ \s ; ( ) , ' \" ] + / )
222225 ) ) ,
223226
227+ // CASE expression: CASE ... END bracketed as a structural unit so that END
228+ // is consumed before the outer function_call's closing ')' can grab it.
229+ case_expression : $ => prec ( 3 , seq (
230+ caseInsensitive ( 'CASE' ) ,
231+ repeat ( $ . case_body_token ) ,
232+ caseInsensitive ( 'END' )
233+ ) ) ,
234+
235+ case_body_token : $ => choice (
236+ caseInsensitive ( 'WHEN' ) ,
237+ caseInsensitive ( 'THEN' ) ,
238+ caseInsensitive ( 'ELSE' ) ,
239+ $ . string ,
240+ $ . number ,
241+ $ . case_expression ,
242+ $ . cast_expression ,
243+ $ . function_call ,
244+ $ . subquery , // also handles IN-lists like ('a', 'b')
245+ token ( '=' ) , token ( '!=' ) , token ( '<>' ) , token ( '<=' ) , token ( '>=' ) ,
246+ token ( '<' ) , token ( '>' ) ,
247+ token ( '+' ) , token ( '-' ) , token ( '*' ) , token ( '/' ) , token ( '%' ) , token ( '||' ) , token ( '::' ) ,
248+ caseInsensitive ( 'AND' ) ,
249+ caseInsensitive ( 'OR' ) ,
250+ caseInsensitive ( 'NOT' ) ,
251+ caseInsensitive ( 'IN' ) ,
252+ caseInsensitive ( 'IS' ) ,
253+ caseInsensitive ( 'NULL' ) ,
254+ caseInsensitive ( 'LIKE' ) ,
255+ caseInsensitive ( 'ILIKE' ) ,
256+ caseInsensitive ( 'BETWEEN' ) ,
257+ token ( ',' ) ,
258+ token ( '.' ) ,
259+ $ . identifier ,
260+ ) ,
261+
224262 // CAST/TRY_CAST expression: CAST(expr AS type) or TRY_CAST(expr AS type)
225263 // Higher precedence than function_call to win over treating CAST as a regular function
226264 cast_expression : $ => prec ( 3 , seq (
@@ -359,6 +397,8 @@ module.exports = grammar({
359397 $ . number ,
360398 $ . string ,
361399 '*' ,
400+ // CASE expression
401+ $ . case_expression ,
362402 // CAST/TRY_CAST expression
363403 $ . cast_expression ,
364404 // Nested function call
0 commit comments