Skip to main content

sql_fun_sqlast/sem/scalar_expr/
cast_expr.rs

1use sql_fun_core::IVec;
2
3use crate::{
4    sem::{
5        AnalysisError, AnalysisProblem, FromClause, FullName, ParseContext, SemScalarExpr,
6        TypeReference, WithClause, analyze_scaler_expr,
7    },
8    syn::{Opt, ScanToken},
9};
10
11use super::{AnalyzeScalarExpr, SemScalarExprNode};
12
13/// implicit cast expression
14#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
15pub struct ImplicitCastExpr {
16    value: Box<SemScalarExpr>,
17    cast_target: TypeReference,
18}
19
20impl ImplicitCastExpr {
21    /// create a implicit cast expression
22    #[must_use]
23    pub fn new(value: &SemScalarExpr, cast_target: &TypeReference) -> Self {
24        Self {
25            value: Box::new(value.clone()),
26            cast_target: cast_target.clone(),
27        }
28    }
29}
30
31impl SemScalarExprNode for ImplicitCastExpr {
32    fn get_type(&self) -> Option<TypeReference> {
33        Some(self.cast_target.clone())
34    }
35
36    fn is_not_null(&self) -> Option<bool> {
37        self.value.is_not_null()
38    }
39}
40
41/// explicit cast expression
42#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
43pub struct TypeCastExpr {
44    target_type: TypeReference,
45    arg: Box<SemScalarExpr>,
46}
47
48impl TypeCastExpr {
49    fn new(target_type: TypeReference, arg: SemScalarExpr) -> TypeCastExpr {
50        Self {
51            target_type,
52            arg: Box::new(arg),
53        }
54    }
55}
56
57impl SemScalarExprNode for TypeCastExpr {
58    fn get_type(&self) -> Option<TypeReference> {
59        Some(self.target_type.clone())
60    }
61
62    fn is_not_null(&self) -> Option<bool> {
63        self.arg.is_not_null()
64    }
65}
66
67impl<TParseContext> AnalyzeScalarExpr<TParseContext, crate::syn::TypeCast> for TypeCastExpr
68where
69    TParseContext: ParseContext,
70{
71    fn analyze_scalar_expr(
72        mut context: TParseContext,
73        with_clause: &WithClause,
74        from_clause: &FromClause,
75        syn: crate::syn::TypeCast,
76        tokens: &IVec<ScanToken>,
77    ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
78        let Some(arg) = syn.get_arg().as_inner() else {
79            AnalysisError::raise_unexpected_none("typecast.arg")?
80        };
81        let Some(target_type) = syn.get_type_name().as_inner() else {
82            AnalysisError::raise_unexpected_none("typecast.type_name")?
83        };
84        let target_type = TypeReference::from_full_name(FullName::try_from(target_type)?);
85
86        let (arg, new_context) =
87            analyze_scaler_expr(context, with_clause, from_clause, arg, tokens)?;
88        context = new_context;
89
90        if let Some(from_type) = arg.get_type() {
91            let cast = context.get_explicit_cast(&from_type, &target_type);
92            if cast.is_none() {
93                context.report_problem(AnalysisProblem::explicit_cast_not_defined(
94                    &from_type,
95                    &target_type,
96                ))?;
97            }
98        }
99
100        Ok((
101            SemScalarExpr::TypeCast(Self::new(target_type, arg)),
102            context,
103        ))
104    }
105}