66#include " sql_parser/tokenizer.h"
77#include " sql_parser/ast.h"
88#include " sql_parser/arena.h"
9+ #include " sql_parser/user_variable.h"
910
1011namespace sql_parser {
1112
@@ -99,19 +100,27 @@ class ExpressionParser {
99100 switch (t.type ) {
100101 case TokenType::TK_INTEGER : {
101102 tok_.skip ();
102- return make_node (arena_, NodeType::NODE_LITERAL_INT , t. text );
103+ return make_node_from_token (arena_, NodeType::NODE_LITERAL_INT , t);
103104 }
104105 case TokenType::TK_FLOAT : {
105106 tok_.skip ();
106- return make_node (arena_, NodeType::NODE_LITERAL_FLOAT , t.text );
107+ return make_node_from_token (arena_, NodeType::NODE_LITERAL_FLOAT , t);
108+ }
109+ case TokenType::TK_HEX_LITERAL : {
110+ tok_.skip ();
111+ return make_node_from_token (arena_, NodeType::NODE_LITERAL_HEX , t);
112+ }
113+ case TokenType::TK_BIT_LITERAL : {
114+ tok_.skip ();
115+ return make_node_from_token (arena_, NodeType::NODE_LITERAL_BIT , t);
107116 }
108117 case TokenType::TK_STRING : {
109118 tok_.skip ();
110- return make_node (arena_, NodeType::NODE_LITERAL_STRING , t. text );
119+ return make_node_from_token (arena_, NodeType::NODE_LITERAL_STRING , t);
111120 }
112121 case TokenType::TK_NULL : {
113122 tok_.skip ();
114- return make_node (arena_, NodeType::NODE_LITERAL_NULL , t. text );
123+ return make_node_from_token (arena_, NodeType::NODE_LITERAL_NULL , t);
115124 }
116125 case TokenType::TK_TRUE :
117126 case TokenType::TK_FALSE : {
@@ -150,6 +159,10 @@ class ExpressionParser {
150159 static_cast <uint32_t >((name.text .ptr + name.text .len ) - t.text .ptr )};
151160 return make_node (arena_, NodeType::NODE_COLUMN_REF , full);
152161 }
162+ case TokenType::TK_USER_VARIABLE : {
163+ tok_.skip ();
164+ return make_mysql_user_variable_node (arena_, t);
165+ }
153166 case TokenType::TK_DOUBLE_AT : {
154167 // System variable: @@name or @@scope.name
155168 tok_.skip ();
@@ -174,19 +187,26 @@ class ExpressionParser {
174187 AstNode* operand = parse (Precedence::UNARY );
175188 if (!operand) return nullptr ;
176189 AstNode* node = make_node (arena_, NodeType::NODE_UNARY_OP , t.text );
190+ set_span_through_node_ (node, t.source , operand);
177191 node->add_child (operand);
178192 return node;
179193 }
180194 case TokenType::TK_PLUS : {
181195 // Unary plus
182196 tok_.skip ();
183- return parse (Precedence::UNARY );
197+ AstNode* operand = parse (Precedence::UNARY );
198+ if (!operand) return nullptr ;
199+ AstNode* node = make_node (arena_, NodeType::NODE_UNARY_OP , t.text );
200+ set_span_through_node_ (node, t.source , operand);
201+ node->add_child (operand);
202+ return node;
184203 }
185204 case TokenType::TK_NOT : {
186205 tok_.skip ();
187206 AstNode* operand = parse (Precedence::NOT );
188207 if (!operand) return nullptr ;
189208 AstNode* node = make_node (arena_, NodeType::NODE_UNARY_OP , t.text );
209+ set_span_through_node_ (node, t.source , operand);
190210 node->add_child (operand);
191211 return node;
192212 }
@@ -266,7 +286,12 @@ class ExpressionParser {
266286 return parse_postfix (tuple);
267287 }
268288 if (tok_.peek ().type == TokenType::TK_RPAREN ) {
269- tok_.skip ();
289+ Token close = tok_.next_token ();
290+ AstNode* wrapper = make_node (arena_, NodeType::NODE_EXPRESSION );
291+ wrapper->set_source (StringRef{t.source .ptr ,
292+ static_cast <uint32_t >(close.source .ptr + close.source .len - t.source .ptr )});
293+ wrapper->add_child (expr);
294+ return parse_postfix (wrapper);
270295 }
271296 // Check for postfix: (expr).field or (expr)[index]
272297 return parse_postfix (expr);
@@ -287,11 +312,39 @@ class ExpressionParser {
287312 }
288313 }
289314
315+ static void set_span_through_node_ (AstNode* node, StringRef start,
316+ const AstNode* end_node) {
317+ if (!node || !start.ptr || !end_node) return ;
318+ StringRef end = end_node->source ();
319+ if (end.empty ()) end = end_node->value ();
320+ if (!end.ptr || end.ptr < start.ptr ) return ;
321+ node->set_source (StringRef{start.ptr ,
322+ static_cast <uint32_t >(end.ptr + end.len - start.ptr )});
323+ }
324+
290325 AstNode* parse_identifier_or_function (const Token& name_token) {
291326 // Check for function call: name(
292327 if (tok_.peek ().type == TokenType::TK_LPAREN ) {
293328 tok_.skip (); // consume (
294329 AstNode* func = make_node (arena_, NodeType::NODE_FUNCTION_CALL , name_token.text );
330+ // CAST uses `CAST(expr AS type)` rather than a comma-separated
331+ // argument list. Model it as a function call so consumers can
332+ // reject or handle the expression without leaving valid input
333+ // unconsumed.
334+ if (name_token.text .equals_ci (" CAST" , 4 )) {
335+ AstNode* arg = parse ();
336+ if (!arg || tok_.peek ().type != TokenType::TK_AS ) return func;
337+ func->add_child (arg);
338+ tok_.skip ();
339+ Token type = tok_.next_token ();
340+ if (type.type == TokenType::TK_EOF ||
341+ type.type == TokenType::TK_RPAREN ) {
342+ return func;
343+ }
344+ func->add_child (make_node (arena_, NodeType::NODE_IDENTIFIER , type.text ));
345+ if (tok_.peek ().type == TokenType::TK_RPAREN ) tok_.skip ();
346+ return func;
347+ }
295348 // Parse argument list
296349 if (tok_.peek ().type != TokenType::TK_RPAREN ) {
297350 while (true ) {
0 commit comments