@@ -1072,6 +1072,20 @@ func (p *Parser) parsePrimaryExpression() (ast.ScalarExpression, error) {
10721072 return & ast.UnaryExpression {UnaryExpressionType : "BitwiseNot" , Expression : expr }, nil
10731073 }
10741074 return nil , fmt .Errorf ("unexpected token in expression: %s" , p .curTok .Literal )
1075+ case TokenLeft :
1076+ // LEFT can be a function name (string function)
1077+ if p .peekTok .Type == TokenLParen {
1078+ p .nextToken () // consume LEFT
1079+ return p .parseLeftFunctionCall ()
1080+ }
1081+ return nil , fmt .Errorf ("unexpected token in expression: %s" , p .curTok .Literal )
1082+ case TokenRight :
1083+ // RIGHT can be a function name (string function)
1084+ if p .peekTok .Type == TokenLParen {
1085+ p .nextToken () // consume RIGHT
1086+ return p .parseRightFunctionCall ()
1087+ }
1088+ return nil , fmt .Errorf ("unexpected token in expression: %s" , p .curTok .Literal )
10751089 case TokenIdent :
10761090 // Check if it's a global variable reference (starts with @@)
10771091 if strings .HasPrefix (p .curTok .Literal , "@@" ) {
@@ -5917,6 +5931,72 @@ func (p *Parser) parseIdentityFunctionCall() (ast.ScalarExpression, error) {
59175931 return identity , nil
59185932}
59195933
5934+ // parseLeftFunctionCall parses LEFT(string, count)
5935+ func (p * Parser ) parseLeftFunctionCall () (ast.ScalarExpression , error ) {
5936+ // Already consumed LEFT, now on (
5937+ if p .curTok .Type != TokenLParen {
5938+ return nil , fmt .Errorf ("expected ( after LEFT, got %s" , p .curTok .Literal )
5939+ }
5940+ p .nextToken () // consume (
5941+
5942+ var params []ast.ScalarExpression
5943+
5944+ // Parse parameters
5945+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
5946+ param , err := p .parseScalarExpression ()
5947+ if err != nil {
5948+ return nil , err
5949+ }
5950+ params = append (params , param )
5951+
5952+ if p .curTok .Type == TokenComma {
5953+ p .nextToken () // consume ,
5954+ } else {
5955+ break
5956+ }
5957+ }
5958+
5959+ if p .curTok .Type != TokenRParen {
5960+ return nil , fmt .Errorf ("expected ) in LEFT function, got %s" , p .curTok .Literal )
5961+ }
5962+ p .nextToken () // consume )
5963+
5964+ return & ast.LeftFunctionCall {Parameters : params }, nil
5965+ }
5966+
5967+ // parseRightFunctionCall parses RIGHT(string, count)
5968+ func (p * Parser ) parseRightFunctionCall () (ast.ScalarExpression , error ) {
5969+ // Already consumed RIGHT, now on (
5970+ if p .curTok .Type != TokenLParen {
5971+ return nil , fmt .Errorf ("expected ( after RIGHT, got %s" , p .curTok .Literal )
5972+ }
5973+ p .nextToken () // consume (
5974+
5975+ var params []ast.ScalarExpression
5976+
5977+ // Parse parameters
5978+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
5979+ param , err := p .parseScalarExpression ()
5980+ if err != nil {
5981+ return nil , err
5982+ }
5983+ params = append (params , param )
5984+
5985+ if p .curTok .Type == TokenComma {
5986+ p .nextToken () // consume ,
5987+ } else {
5988+ break
5989+ }
5990+ }
5991+
5992+ if p .curTok .Type != TokenRParen {
5993+ return nil , fmt .Errorf ("expected ) in RIGHT function, got %s" , p .curTok .Literal )
5994+ }
5995+ p .nextToken () // consume )
5996+
5997+ return & ast.RightFunctionCall {Parameters : params }, nil
5998+ }
5999+
59206000// parsePredictTableReference parses PREDICT(...) in FROM clause
59216001// PREDICT(MODEL = expression, DATA = table AS alias, RUNTIME=ident) WITH (columns) AS alias
59226002func (p * Parser ) parsePredictTableReference () (* ast.PredictTableReference , error ) {
0 commit comments