|
1 | 1 | package parser |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "math" |
4 | 5 | "strconv" |
5 | 6 | "strings" |
6 | 7 |
|
@@ -100,6 +101,34 @@ func (p *Parser) parseExpressionList() []ast.Expression { |
100 | 101 | return exprs |
101 | 102 | } |
102 | 103 |
|
| 104 | +// parseFunctionArgumentList parses arguments for function calls, stopping at SETTINGS |
| 105 | +func (p *Parser) parseFunctionArgumentList() []ast.Expression { |
| 106 | + var exprs []ast.Expression |
| 107 | + |
| 108 | + if p.currentIs(token.RPAREN) || p.currentIs(token.EOF) || p.currentIs(token.SETTINGS) { |
| 109 | + return exprs |
| 110 | + } |
| 111 | + |
| 112 | + expr := p.parseExpression(LOWEST) |
| 113 | + if expr != nil { |
| 114 | + exprs = append(exprs, expr) |
| 115 | + } |
| 116 | + |
| 117 | + for p.currentIs(token.COMMA) { |
| 118 | + p.nextToken() |
| 119 | + // Stop if we hit SETTINGS |
| 120 | + if p.currentIs(token.SETTINGS) { |
| 121 | + break |
| 122 | + } |
| 123 | + expr := p.parseExpression(LOWEST) |
| 124 | + if expr != nil { |
| 125 | + exprs = append(exprs, expr) |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + return exprs |
| 130 | +} |
| 131 | + |
103 | 132 | // parseImplicitAlias handles implicit column aliases like "SELECT 'a' c0" (meaning 'a' AS c0) |
104 | 133 | func (p *Parser) parseImplicitAlias(expr ast.Expression) ast.Expression { |
105 | 134 | // If next token is a plain identifier (not a keyword), treat as implicit alias |
@@ -158,6 +187,8 @@ func (p *Parser) parsePrefixExpression() ast.Expression { |
158 | 187 | return p.parseBoolean() |
159 | 188 | case token.NULL: |
160 | 189 | return p.parseNull() |
| 190 | + case token.NAN, token.INF: |
| 191 | + return p.parseSpecialNumber() |
161 | 192 | case token.MINUS: |
162 | 193 | return p.parseUnaryMinus() |
163 | 194 | case token.NOT: |
@@ -201,9 +232,13 @@ func (p *Parser) parsePrefixExpression() ast.Expression { |
201 | 232 | } |
202 | 233 | return nil |
203 | 234 | default: |
204 | | - // Handle other keywords that can be used as function names |
205 | | - if p.current.Token.IsKeyword() && p.peekIs(token.LPAREN) { |
206 | | - return p.parseKeywordAsFunction() |
| 235 | + // Handle other keywords that can be used as function names or identifiers |
| 236 | + if p.current.Token.IsKeyword() { |
| 237 | + if p.peekIs(token.LPAREN) { |
| 238 | + return p.parseKeywordAsFunction() |
| 239 | + } |
| 240 | + // Keywords like ALL, DEFAULT, etc. can be used as identifiers |
| 241 | + return p.parseKeywordAsIdentifier() |
207 | 242 | } |
208 | 243 | return nil |
209 | 244 | } |
@@ -357,12 +392,33 @@ func (p *Parser) parseFunctionCall(name string, pos token.Position) *ast.Functio |
357 | 392 | } |
358 | 393 |
|
359 | 394 | // Parse arguments |
360 | | - if !p.currentIs(token.RPAREN) { |
361 | | - fn.Arguments = p.parseExpressionList() |
| 395 | + if !p.currentIs(token.RPAREN) && !p.currentIs(token.SETTINGS) { |
| 396 | + fn.Arguments = p.parseFunctionArgumentList() |
| 397 | + } |
| 398 | + |
| 399 | + // Handle SETTINGS inside function call (table functions) |
| 400 | + if p.currentIs(token.SETTINGS) { |
| 401 | + p.nextToken() |
| 402 | + // Parse settings as key=value pairs until ) |
| 403 | + for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) { |
| 404 | + // Just skip the settings for now |
| 405 | + p.nextToken() |
| 406 | + } |
362 | 407 | } |
363 | 408 |
|
364 | 409 | p.expect(token.RPAREN) |
365 | 410 |
|
| 411 | + // Handle IGNORE NULLS / RESPECT NULLS (window function modifiers) |
| 412 | + if p.currentIs(token.IDENT) { |
| 413 | + upper := strings.ToUpper(p.current.Value) |
| 414 | + if upper == "IGNORE" || upper == "RESPECT" { |
| 415 | + p.nextToken() |
| 416 | + if p.currentIs(token.NULLS) { |
| 417 | + p.nextToken() |
| 418 | + } |
| 419 | + } |
| 420 | + } |
| 421 | + |
366 | 422 | // Handle OVER clause for window functions |
367 | 423 | if p.currentIs(token.OVER) { |
368 | 424 | p.nextToken() |
@@ -559,6 +615,21 @@ func (p *Parser) parseNull() ast.Expression { |
559 | 615 | return lit |
560 | 616 | } |
561 | 617 |
|
| 618 | +func (p *Parser) parseSpecialNumber() ast.Expression { |
| 619 | + lit := &ast.Literal{ |
| 620 | + Position: p.current.Pos, |
| 621 | + Type: ast.LiteralFloat, |
| 622 | + } |
| 623 | + switch p.current.Token { |
| 624 | + case token.NAN: |
| 625 | + lit.Value = math.NaN() |
| 626 | + case token.INF: |
| 627 | + lit.Value = math.Inf(1) |
| 628 | + } |
| 629 | + p.nextToken() |
| 630 | + return lit |
| 631 | +} |
| 632 | + |
562 | 633 | func (p *Parser) parseUnaryMinus() ast.Expression { |
563 | 634 | expr := &ast.UnaryExpr{ |
564 | 635 | Position: p.current.Pos, |
@@ -1383,6 +1454,17 @@ func (p *Parser) parseKeywordAsFunction() ast.Expression { |
1383 | 1454 | } |
1384 | 1455 | } |
1385 | 1456 |
|
| 1457 | +func (p *Parser) parseKeywordAsIdentifier() ast.Expression { |
| 1458 | + pos := p.current.Pos |
| 1459 | + name := p.current.Value |
| 1460 | + p.nextToken() |
| 1461 | + |
| 1462 | + return &ast.Identifier{ |
| 1463 | + Position: pos, |
| 1464 | + Parts: []string{name}, |
| 1465 | + } |
| 1466 | +} |
| 1467 | + |
1386 | 1468 | func (p *Parser) parseAsteriskExcept(asterisk *ast.Asterisk) ast.Expression { |
1387 | 1469 | p.nextToken() // skip EXCEPT |
1388 | 1470 |
|
|
0 commit comments