use crate::antlr::strip_numeric_separators;
use crate::tree::ast::expression::{
BooleanLiteral, DecimalLiteral, DoubleLiteral, Expression, IntLiteral, IntervalLiteral,
IntervalUnit, NullLiteral, StringLiteral,
};
use crate::tree::ast::node::Span;
use super::{ExpressionBuilder, IntoExpressionBuilder};
#[derive(Debug)]
pub struct IntLiteralBuilder {
value: i64,
}
impl IntLiteralBuilder {
pub fn new(value: i64) -> Self {
Self { value }
}
}
impl ExpressionBuilder for IntLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: IntLiteral { int: self.value }.into(),
}
}
}
impl IntoExpressionBuilder for IntLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct DoubleLiteralBuilder {
value: f64,
}
impl DoubleLiteralBuilder {
pub fn new(value: f64) -> Self {
Self { value }
}
}
impl ExpressionBuilder for DoubleLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: DoubleLiteral { value: self.value }.into(),
}
}
}
impl IntoExpressionBuilder for DoubleLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct DecimalLiteralBuilder {
unscaled_value: i128,
precision: u32,
scale: u32,
}
impl DecimalLiteralBuilder {
pub fn new(unscaled_value: i128, precision: u32, scale: u32) -> Self {
Self {
unscaled_value,
precision,
scale,
}
}
pub fn from_string(s: &str) -> Result<Self, String> {
let s = strip_numeric_separators(s);
let decimal_pos = s.find('.').unwrap_or(s.len());
let integer_part = &s[..decimal_pos];
let fractional_part = if decimal_pos < s.len() {
&s[decimal_pos + 1..]
} else {
""
};
let scale = fractional_part.len() as u32;
let integer_digit_count = if integer_part.starts_with('-') {
integer_part.len() - 1 } else {
integer_part.len()
};
let precision = (integer_digit_count + scale as usize) as u32;
let unscaled_str = format!("{}{}", integer_part, fractional_part);
let unscaled_value = unscaled_str
.parse::<i128>()
.map_err(|e| format!("Invalid decimal format: {}", e))?;
Ok(Self::new(unscaled_value, precision, scale))
}
}
impl ExpressionBuilder for DecimalLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: DecimalLiteral {
unscaled_value: self.unscaled_value,
precision: self.precision,
scale: self.scale,
}
.into(),
}
}
}
impl IntoExpressionBuilder for DecimalLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct StringLiteralBuilder {
value: String,
}
impl StringLiteralBuilder {
pub fn new(value: impl Into<String>) -> Self {
Self {
value: value.into(),
}
}
}
impl ExpressionBuilder for StringLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: StringLiteral {
value: self.value.clone(),
}
.into(),
}
}
}
impl IntoExpressionBuilder for StringLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct BoolLiteralBuilder {
value: bool,
}
impl BoolLiteralBuilder {
pub fn new(value: bool) -> Self {
Self { value }
}
}
impl ExpressionBuilder for BoolLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: BooleanLiteral { value: self.value }.into(),
}
}
}
impl IntoExpressionBuilder for BoolLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct NullLiteralBuilder;
impl NullLiteralBuilder {
pub fn new() -> Self {
Self
}
}
impl IntoExpressionBuilder for NullLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct IntervalLiteralBuilder {
value: i64,
unit: IntervalUnit,
}
impl IntervalLiteralBuilder {
pub fn new(value: i64, unit: IntervalUnit) -> Self {
Self { value, unit }
}
}
impl ExpressionBuilder for IntervalLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: IntervalLiteral {
value: self.value,
unit: self.unit.clone(),
}
.into(),
}
}
}
impl IntoExpressionBuilder for IntervalLiteralBuilder {
fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
Box::new(self)
}
}
impl Default for NullLiteralBuilder {
fn default() -> Self {
Self::new()
}
}
impl ExpressionBuilder for NullLiteralBuilder {
fn build(&self) -> Expression {
Expression {
span: Span::NONE,
kind: NullLiteral.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use rstest::rstest;
#[rstest]
#[case("123.45", 12345, 5, 2, "positive decimal")]
#[case("-123.45", -12345, 5, 2, "negative decimal - should exclude negative sign from precision")]
#[case("42", 42, 2, 0, "positive integer")]
#[case("-42", -42, 2, 0, "negative integer - should exclude negative sign from precision")]
#[case("1000", 1000, 4, 0, "integer with zero scale")]
#[case("0.123456789", 123456789, 10, 9, "high precision decimal")]
#[case("-0.123456789", -123456789, 10, 9, "negative high precision decimal")]
#[case("0", 0, 1, 0, "zero")]
#[case("-0", 0, 1, 0, "negative zero")]
#[case("1.0", 10, 2, 1, "decimal with trailing zero")]
fn test_decimal_from_string(
#[case] input: &str,
#[case] expected_unscaled: i128,
#[case] expected_precision: u32,
#[case] expected_scale: u32,
#[case] description: &str,
) {
let decimal = DecimalLiteralBuilder::from_string(input).unwrap();
assert_eq!(
decimal.unscaled_value, expected_unscaled,
"Failed for {}: unscaled value mismatch",
description
);
assert_eq!(
decimal.precision, expected_precision,
"Failed for {}: precision mismatch",
description
);
assert_eq!(
decimal.scale, expected_scale,
"Failed for {}: scale mismatch",
description
);
}
#[rstest]
#[case("")]
#[case("abc")]
#[case("1.2.3")]
#[case("--123")]
fn test_decimal_from_string_invalid(#[case] input: &str) {
let result = DecimalLiteralBuilder::from_string(input);
assert!(result.is_err(), "Expected error for input: {}", input);
}
}