(
tokens: &[Token],
pos: &mut usize,
depth: &mut usize,
)
| 193 | } |
| 194 | |
| 195 | fn parse_primary( |
| 196 | tokens: &[Token], |
| 197 | pos: &mut usize, |
| 198 | depth: &mut usize, |
| 199 | ) -> Result<SqlExpr, ExprParseError> { |
| 200 | if *pos >= tokens.len() { |
| 201 | return Err(ExprParseError::UnexpectedEof); |
| 202 | } |
| 203 | |
| 204 | let token = &tokens[*pos]; |
| 205 | |
| 206 | match token.kind { |
| 207 | TokenKind::LParen => { |
| 208 | *depth += 1; |
| 209 | if *depth > MAX_EXPR_DEPTH { |
| 210 | return Err(ExprParseError::DepthLimitExceeded { |
| 211 | max: MAX_EXPR_DEPTH, |
| 212 | }); |
| 213 | } |
| 214 | *pos += 1; |
| 215 | let expr = parse_expr(tokens, pos, depth)?; |
| 216 | *depth -= 1; |
| 217 | expect_token(tokens, pos, TokenKind::RParen, ")")?; |
| 218 | Ok(expr) |
| 219 | } |
| 220 | |
| 221 | TokenKind::Number => { |
| 222 | *pos += 1; |
| 223 | if let Ok(i) = token.text.parse::<i64>() { |
| 224 | Ok(SqlExpr::Literal(Value::Integer(i))) |
| 225 | } else if let Ok(f) = token.text.parse::<f64>() { |
| 226 | Ok(SqlExpr::Literal(Value::Float(f))) |
| 227 | } else { |
| 228 | Err(ExprParseError::InvalidLiteral { |
| 229 | detail: format!("invalid number: '{}'", token.text), |
| 230 | }) |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | TokenKind::StringLit => { |
| 235 | *pos += 1; |
| 236 | Ok(SqlExpr::Literal(Value::String(token.text.clone()))) |
| 237 | } |
| 238 | |
| 239 | TokenKind::Ident => { |
| 240 | let name = token.text.clone(); |
| 241 | let upper = name.to_uppercase(); |
| 242 | *pos += 1; |
| 243 | |
| 244 | match upper.as_str() { |
| 245 | "NULL" => Ok(SqlExpr::Literal(Value::Null)), |
| 246 | "TRUE" => Ok(SqlExpr::Literal(Value::Bool(true))), |
| 247 | "FALSE" => Ok(SqlExpr::Literal(Value::Bool(false))), |
| 248 | "CASE" => parse_case(tokens, pos, depth), |
| 249 | "COALESCE" => { |
| 250 | let args = parse_arg_list(tokens, pos, depth)?; |
| 251 | Ok(SqlExpr::Coalesce(args)) |
| 252 | } |
no test coverage detected