use crate::{Analyzer, TypeContext};
use swamp_semantic::err::ErrorKind;
use swamp_semantic::{BinaryOperator, BinaryOperatorKind, UnaryOperator, UnaryOperatorKind};
use swamp_types::prelude::*;
use tracing::error;
impl Analyzer<'_> {
pub(crate) fn analyze_binary_op(
&mut self,
ast_left: &swamp_ast::Expression,
ast_op: &swamp_ast::BinaryOperator,
ast_right: &swamp_ast::Expression,
) -> Option<(BinaryOperator, TypeRef)> {
let anything_context = TypeContext::new_anything_argument(true); let left = self.analyze_expression(ast_left, &anything_context);
let left_type = &*left.ty.kind;
let right = self.analyze_expression(ast_right, &anything_context);
let right_type = &*right.ty.kind;
let kind = Self::convert_binary_operator_kind(ast_op);
let node = self.to_node(&ast_op.node);
match (&kind, &left_type, &right_type) {
(&BinaryOperatorKind::NoneCoalesce, _left_kind, _right_kind) => {
if let TypeKind::Optional(inner_optional) = &left_type {
if self.types().compatible_with(inner_optional, &right.ty)
|| self.types().compatible_with(&left.ty, &right.ty)
{
let final_type = right.ty.clone();
Some((
BinaryOperator {
left: Box::new(left),
right: Box::new(right.clone()),
kind,
node,
},
final_type,
))
} else {
self.add_err(ErrorKind::ExpectedOptional, &ast_op.node);
None
}
} else {
self.add_err(ErrorKind::ExpectedOptional, &ast_op.node);
None
}
}
(&BinaryOperatorKind::Multiply, TypeKind::VecStorage(inner, _), TypeKind::Int) => {
if *inner.kind != TypeKind::Byte {
return None;
}
Some((
BinaryOperator {
left: Box::new(left),
right: Box::new(right),
kind,
node,
},
self.shared.state.types.string(),
))
}
(
&BinaryOperatorKind::Multiply,
TypeKind::StringStorage(..) | TypeKind::String(..),
TypeKind::Int,
) => Some((
BinaryOperator {
left: Box::new(left),
right: Box::new(right),
kind,
node,
},
self.shared.state.types.string(),
)),
(
&BinaryOperatorKind::Add,
TypeKind::VecStorage(inner, _),
TypeKind::StringStorage(..),
) => {
if *inner.kind != TypeKind::Byte {
return None;
}
Some((
BinaryOperator {
left: Box::new(left),
right: Box::new(right),
kind,
node,
},
self.shared.state.types.string(),
))
}
(
BinaryOperatorKind::Equal
| BinaryOperatorKind::NotEqual
| BinaryOperatorKind::GreaterThan
| BinaryOperatorKind::GreaterEqual
| BinaryOperatorKind::LessThan
| BinaryOperatorKind::LessEqual,
_,
_,
) => {
if !self.shared.state.types.compatible_with(&left.ty, &right.ty) {
self.add_err(
ErrorKind::IncompatibleTypes {
expected: left.ty.clone(),
found: right.ty.clone(),
},
&ast_op.node,
);
return None;
}
Some((
BinaryOperator {
left: Box::new(left),
right: Box::new(right),
kind,
node,
},
self.shared.state.types.bool(),
))
}
_ => {
if !self.shared.state.types.compatible_with(&left.ty, &right.ty) {
self.add_err_resolved(
ErrorKind::IncompatibleTypes {
expected: left.ty.clone(),
found: right.ty.clone(),
},
&node,
);
return None;
}
let result_type = left.ty.clone();
Some((
BinaryOperator {
left: Box::new(left),
right: Box::new(right),
kind,
node,
},
result_type,
))
}
}
}
pub(crate) fn analyze_unary_op(
&mut self,
ast_op: &swamp_ast::UnaryOperator,
ast_left: &swamp_ast::Expression,
) -> Option<(UnaryOperator, TypeRef)> {
let (node, left, kind) = match ast_op {
swamp_ast::UnaryOperator::Not(node) => {
let bool_type = self.shared.state.types.bool();
let context = TypeContext::new_argument(&bool_type, false);
let left = self.analyze_expression(ast_left, &context);
if !matches!(&*left.ty.kind, &TypeKind::Bool) {
error!(
ty=?left.ty ,
"not expects bool"
);
}
(node, left, UnaryOperatorKind::Not)
}
swamp_ast::UnaryOperator::Negate(node) => {
let context = TypeContext::new_anything_argument(false);
let left = self.analyze_expression(ast_left, &context);
(node, left, UnaryOperatorKind::Negate)
}
swamp_ast::UnaryOperator::BorrowMutRef(_) => {
panic!("unary borrow should have been handled")
}
};
Some((
UnaryOperator {
left: Box::new(left.clone()),
kind,
node: self.to_node(node),
},
left.ty,
))
}
const fn convert_binary_operator_kind(
binary_operator: &swamp_ast::BinaryOperator,
) -> BinaryOperatorKind {
match binary_operator.kind {
swamp_ast::BinaryOperatorKind::Add => BinaryOperatorKind::Add,
swamp_ast::BinaryOperatorKind::Subtract => BinaryOperatorKind::Subtract,
swamp_ast::BinaryOperatorKind::Multiply => BinaryOperatorKind::Multiply,
swamp_ast::BinaryOperatorKind::Divide => BinaryOperatorKind::Divide,
swamp_ast::BinaryOperatorKind::Modulo => BinaryOperatorKind::Modulo,
swamp_ast::BinaryOperatorKind::LogicalOr => BinaryOperatorKind::LogicalOr,
swamp_ast::BinaryOperatorKind::LogicalAnd => BinaryOperatorKind::LogicalAnd,
swamp_ast::BinaryOperatorKind::Equal => BinaryOperatorKind::Equal,
swamp_ast::BinaryOperatorKind::NotEqual => BinaryOperatorKind::NotEqual,
swamp_ast::BinaryOperatorKind::LessThan => BinaryOperatorKind::LessThan,
swamp_ast::BinaryOperatorKind::LessEqual => BinaryOperatorKind::LessEqual,
swamp_ast::BinaryOperatorKind::GreaterThan => BinaryOperatorKind::GreaterThan,
swamp_ast::BinaryOperatorKind::GreaterEqual => BinaryOperatorKind::GreaterEqual,
swamp_ast::BinaryOperatorKind::NoneCoalescingOperator => {
BinaryOperatorKind::NoneCoalesce
}
}
}
}