pub use vb6core::types::{ArrayBound, TypeInfo, VBType};
use crate::error::{Result, SemanticError, SourceLocation};
pub struct TypeChecker {
}
impl TypeChecker {
pub fn new() -> Self {
Self {}
}
pub fn check_assignment(
&self,
target_type: &TypeInfo,
source_type: &TypeInfo,
_location: &SourceLocation,
) -> Result<()> {
if source_type.can_assign_to(target_type) {
Ok(())
} else {
Err(SemanticError::TypeMismatch {
expected: target_type.to_string(),
found: source_type.to_string(),
location: _location.clone(),
})
}
}
pub fn check_operation(
&self,
left_type: &TypeInfo,
right_type: &TypeInfo,
_operation: &str,
_location: &SourceLocation,
) -> Result<TypeInfo> {
if matches!(left_type.kind, VBType::Variant) || matches!(right_type.kind, VBType::Variant) {
return Ok(TypeInfo::variant());
}
if self.is_numeric(&left_type.kind) && self.is_numeric(&right_type.kind) {
return Ok(self.promote_numeric_types(left_type, right_type));
}
if matches!(left_type.kind, VBType::String) || matches!(right_type.kind, VBType::String) {
return Ok(TypeInfo::string());
}
Ok(TypeInfo::variant())
}
fn is_numeric(&self, kind: &VBType) -> bool {
matches!(
kind,
VBType::Integer
| VBType::Long
| VBType::Single
| VBType::Double
| VBType::Currency
| VBType::Byte
)
}
fn promote_numeric_types(&self, left: &TypeInfo, right: &TypeInfo) -> TypeInfo {
use VBType::*;
let promoted = match (&left.kind, &right.kind) {
(Double, _) | (_, Double) => Double,
(Currency, _) | (_, Currency) => Currency,
(Single, _) | (_, Single) => Single,
(Long, _) | (_, Long) => Long,
(Integer, _) | (_, Integer) => Integer,
(Byte, Byte) => Byte,
_ => Variant,
};
TypeInfo::new(promoted)
}
}
impl Default for TypeChecker {
fn default() -> Self {
Self::new()
}
}