use std::{
fmt::{Display, Formatter},
ops::RangeInclusive,
};
use antlr_rust::parser_rule_context::ParserRuleContext;
use crate::{
antlr::interval,
func::def::SpecialPosition,
sql::expression::{
literal::{BooleanLiteral, DecimalLiteral, IntegerLiteral, NullLiteral, StringLiteral},
SQLExpression,
},
types::{Type, BOOLEAN, DOUBLE, INT, STRING, UNKNOWN},
write_utils::Indent,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExpressionTranslation {
pub sql: SQLExpression,
pub typ: Type,
pub span: Option<RangeInclusive<usize>>,
pub special: Option<SpecialPosition>,
pub nested_special: Vec<(SpecialPosition, RangeInclusive<usize>)>,
}
impl ExpressionTranslation {
pub fn with_defaults(typ: Type, sql: SQLExpression) -> Self {
Self {
sql,
typ,
span: None,
special: None,
nested_special: Vec::new(),
}
}
pub fn with_span<'a, T>(mut self, tree: &T) -> Self
where
T: ParserRuleContext<'a>,
{
self.span = Some(interval(tree));
self
}
pub fn with_special(mut self, position: SpecialPosition) -> Self {
self.special = Some(position);
self
}
pub fn with_nested_special(
mut self,
position: SpecialPosition,
span: RangeInclusive<usize>,
) -> Self {
self.nested_special.push((position, span));
self
}
}
impl Display for ExpressionTranslation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Translation yields type:\n{}\n\ninto sql:\n", self.typ,)?;
self.sql.fmt_indented(f, Indent::default().nested())
}
}
impl Default for ExpressionTranslation {
fn default() -> Self {
Self {
sql: NullLiteral::default().into(),
typ: UNKNOWN,
span: None,
special: None,
nested_special: Vec::new(),
}
}
}
impl TryFrom<crate::tree::ast::expression::Expression> for ExpressionTranslation {
type Error = anyhow::Error;
fn try_from(expr: crate::tree::ast::expression::Expression) -> anyhow::Result<Self> {
use crate::tree::ast::expression::ExpressionKind;
match expr.kind {
ExpressionKind::BooleanLiteral(lit) => Ok(Self::with_defaults(
BOOLEAN,
BooleanLiteral { value: lit.value }.into(),
)),
ExpressionKind::IntLiteral(lit) => Ok(Self::with_defaults(
INT,
IntegerLiteral::from_int(lit.int).into(),
)),
ExpressionKind::StringLiteral(lit) => Ok(Self::with_defaults(
STRING,
StringLiteral::new(&lit.value).into(),
)),
ExpressionKind::NullLiteral(_) => {
Ok(Self::with_defaults(UNKNOWN, NullLiteral::default().into()))
}
ExpressionKind::DecimalLiteral(lit) => {
let mut s = lit.unscaled_value.to_string();
let negative = s.starts_with('-');
if negative {
s = s[1..].to_string();
}
while s.len() <= lit.scale as usize {
s = format!("0{}", s);
}
let decimal_pos = s.len() - lit.scale as usize;
s.insert(decimal_pos, '.');
if negative {
s = format!("-{}", s);
}
Ok(Self::with_defaults(DOUBLE, DecimalLiteral::new(&s).into()))
}
other => anyhow::bail!(
"Expression to ExpressionTranslation only supports literals, got: {other:?}",
),
}
}
}