More work on type resolution, WIP.
This commit is contained in:
parent
21fa082b44
commit
dae482ef78
@ -1,6 +1,9 @@
|
|||||||
|
mod number
|
||||||
mod ops
|
mod ops
|
||||||
mod print
|
mod print
|
||||||
mod string
|
mod string
|
||||||
|
|
||||||
|
pub use number::*
|
||||||
|
pub use ops::*
|
||||||
pub use print::*
|
pub use print::*
|
||||||
pub use string::*
|
pub use string::*
|
||||||
|
|||||||
31
dm-core/src/number.dm
Normal file
31
dm-core/src/number.dm
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
pub extern class Int end
|
||||||
|
|
||||||
|
pub extern class Double end
|
||||||
|
|
||||||
|
impl Add for Int
|
||||||
|
intrinsic fn add(right: Self::Right) -> Self
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Add<Right = Double, Result = Double> for Int
|
||||||
|
intrinsic fn add(right: Self::Right) -> Self::Result
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Add<Right = String, Result = String> for Int
|
||||||
|
intrinsic fn add(right: Self::Right) -> Self::Result
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Multiply for Int
|
||||||
|
intrinsic fn multiply(right: Self::Right) -> Self::Result
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Multiply<Right = Double, Result = Double> for Int
|
||||||
|
intrinsic fn multiply(right: Self::Right) -> Self::Result
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Negate for Int
|
||||||
|
intrinsic fn negate() -> Self::Result
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Negate for Double
|
||||||
|
intrinsic fn negate() -> Self::Result
|
||||||
|
end
|
||||||
@ -4,3 +4,16 @@ pub trait Add
|
|||||||
|
|
||||||
fn add(right: Self::Right) -> Self::Result
|
fn add(right: Self::Right) -> Self::Result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pub trait Multiply
|
||||||
|
type Right = Self
|
||||||
|
type Result = Self
|
||||||
|
|
||||||
|
fn multiply(right: Self::Right) -> Self::Result
|
||||||
|
end
|
||||||
|
|
||||||
|
pub trait Negate
|
||||||
|
type Result = Self
|
||||||
|
|
||||||
|
fn negate() -> Self::Result
|
||||||
|
end
|
||||||
|
|||||||
@ -2,4 +2,14 @@ pub extern class String
|
|||||||
pub extern fn len() -> Long
|
pub extern fn len() -> Long
|
||||||
end
|
end
|
||||||
|
|
||||||
intrinsic impl<T> Add<Right = T> for String end
|
impl Add for String
|
||||||
|
intrinsic fn add
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Add<Right = Int> for String
|
||||||
|
intrinsic fn add
|
||||||
|
end
|
||||||
|
|
||||||
|
impl Add<Right = Double> for String
|
||||||
|
intrinsic fn add
|
||||||
|
end
|
||||||
|
|||||||
@ -5,6 +5,34 @@ use crate::semantic_analysis::type_info::{FunctionTypeInfo, InstanceTypeInfo, Ty
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn add_primitive_symbols_and_type_infos(ctx: &mut AnalysisContext, global_scope_id: ScopeId) {
|
pub fn add_primitive_symbols_and_type_infos(ctx: &mut AnalysisContext, global_scope_id: ScopeId) {
|
||||||
|
let int_class_symbol = Symbol::Class(ClassSymbol::new(
|
||||||
|
"Int".into(),
|
||||||
|
None,
|
||||||
|
"core::Int".into(),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
HashMap::new(),
|
||||||
|
HashMap::new(),
|
||||||
|
));
|
||||||
|
let int_symbol_id = ctx
|
||||||
|
.try_insert_symbol_in_scope(int_class_symbol, global_scope_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let double_symbol = Symbol::Class(ClassSymbol::new(
|
||||||
|
"Double".into(),
|
||||||
|
None,
|
||||||
|
"core::Double".into(),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
HashMap::new(),
|
||||||
|
HashMap::new(),
|
||||||
|
));
|
||||||
|
let _double_symbol_id = ctx
|
||||||
|
.try_insert_symbol_in_scope(double_symbol, global_scope_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let int_instance_type_info_id = ctx.instance_type(int_symbol_id);
|
||||||
|
|
||||||
let string_len_symbol = Symbol::Function(FunctionSymbol::new(
|
let string_len_symbol = Symbol::Function(FunctionSymbol::new(
|
||||||
"len".into(),
|
"len".into(),
|
||||||
None,
|
None,
|
||||||
@ -38,11 +66,9 @@ pub fn add_primitive_symbols_and_type_infos(ctx: &mut AnalysisContext, global_sc
|
|||||||
|
|
||||||
ctx.associate_symbol_to_type(string_class_symbol_id, string_instance_type_info_id);
|
ctx.associate_symbol_to_type(string_class_symbol_id, string_instance_type_info_id);
|
||||||
|
|
||||||
let string_len_return_type_info_id = ctx.insert_type_info(TypeInfo::Int);
|
|
||||||
|
|
||||||
let string_len_type_info = TypeInfo::Function(FunctionTypeInfo::new(
|
let string_len_type_info = TypeInfo::Function(FunctionTypeInfo::new(
|
||||||
vec![],
|
vec![],
|
||||||
string_len_return_type_info_id,
|
int_instance_type_info_id,
|
||||||
Some(string_instance_type_info_id),
|
Some(string_instance_type_info_id),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,6 @@ pub fn to_ir_type_info(ctx: &AnalysisContext, sa_type_info: &TypeInfo) -> IrType
|
|||||||
IrTypeInfo::Instance(IrInstanceTypeInfo::new(class_symbol.fqn_owned()))
|
IrTypeInfo::Instance(IrInstanceTypeInfo::new(class_symbol.fqn_owned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeInfo::Int => IrTypeInfo::Int,
|
|
||||||
TypeInfo::Double => IrTypeInfo::Double,
|
|
||||||
TypeInfo::Void => IrTypeInfo::Void,
|
TypeInfo::Void => IrTypeInfo::Void,
|
||||||
_ => {
|
_ => {
|
||||||
panic!("BUG! Unknown sa_type_info: {:?}", sa_type_info);
|
panic!("BUG! Unknown sa_type_info: {:?}", sa_type_info);
|
||||||
@ -27,9 +25,7 @@ pub fn return_type_info_to_ir_type_info(
|
|||||||
return_type_info: &TypeInfo,
|
return_type_info: &TypeInfo,
|
||||||
) -> Option<IrTypeInfo> {
|
) -> Option<IrTypeInfo> {
|
||||||
match return_type_info {
|
match return_type_info {
|
||||||
TypeInfo::Instance(_) | TypeInfo::Int | TypeInfo::Double => {
|
TypeInfo::Instance(_) => Some(to_ir_type_info(ctx, return_type_info)),
|
||||||
Some(to_ir_type_info(ctx, return_type_info))
|
|
||||||
}
|
|
||||||
TypeInfo::Void => None,
|
TypeInfo::Void => None,
|
||||||
_ => panic!("BUG! Unknown return_type_info: {:?}", return_type_info),
|
_ => panic!("BUG! Unknown return_type_info: {:?}", return_type_info),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,8 +19,6 @@ pub fn get_name_for_type<'ctx>(type_info: &TypeInfo, ctx: &'ctx AnalysisContext)
|
|||||||
let class_symbol = &ctx.symbols()[class_symbol_id];
|
let class_symbol = &ctx.symbols()[class_symbol_id];
|
||||||
class_symbol.declared_name()
|
class_symbol.declared_name()
|
||||||
}
|
}
|
||||||
TypeInfo::Int => "Int",
|
|
||||||
TypeInfo::Double => "Double",
|
|
||||||
TypeInfo::Void => "Void",
|
TypeInfo::Void => "Void",
|
||||||
TypeInfo::__Error => panic!("TypeInfo::__Error should never be shown to the user."),
|
TypeInfo::__Error => panic!("TypeInfo::__Error should never be shown to the user."),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -366,6 +366,10 @@ impl AnalysisContext {
|
|||||||
.expect(&format!("node_id {} has no associated type", node_id))
|
.expect(&format!("node_id {} has no associated type", node_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_type_info_id_for_node_2(&self, node_id: NodeId) -> Option<TypeInfoId> {
|
||||||
|
self.state.nodes_to_type_infos.get(&node_id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_type_info_for_node(&self, node_id: NodeId) -> &TypeInfo {
|
pub fn get_type_info_for_node(&self, node_id: NodeId) -> &TypeInfo {
|
||||||
let type_info_id = self.get_type_info_id_for_node(node_id);
|
let type_info_id = self.get_type_info_id_for_node(node_id);
|
||||||
self.state
|
self.state
|
||||||
@ -402,6 +406,10 @@ impl AnalysisContext {
|
|||||||
*symbol_type_info_id
|
*symbol_type_info_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_type_info_id_for_symbol(&self, symbol_id: SymbolId) -> Option<TypeInfoId> {
|
||||||
|
self.state.symbols_to_type_infos.get(&symbol_id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option<SymbolId> {
|
pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option<SymbolId> {
|
||||||
// This is quite naive and probably very slow; we will certainly use trees of HashMaps (or
|
// This is quite naive and probably very slow; we will certainly use trees of HashMaps (or
|
||||||
// structs with a HashMap and children) to represent the fqn hierarchy.
|
// structs with a HashMap and children) to represent the fqn hierarchy.
|
||||||
@ -427,16 +435,11 @@ impl AnalysisContext {
|
|||||||
self.state.nodes_to_scopes.get(&node_id).cloned()
|
self.state.nodes_to_scopes.get(&node_id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_class_type(
|
pub fn make_class_type(&mut self, class_symbol_id: SymbolId) -> TypeInfoId {
|
||||||
&mut self,
|
|
||||||
class_symbol_id: SymbolId,
|
|
||||||
constructor_symbol_id: Option<SymbolId>,
|
|
||||||
) -> TypeInfoId {
|
|
||||||
if let Some(type_info_id) = self.state.symbols_to_type_infos.get(&class_symbol_id) {
|
if let Some(type_info_id) = self.state.symbols_to_type_infos.get(&class_symbol_id) {
|
||||||
*type_info_id
|
*type_info_id
|
||||||
} else {
|
} else {
|
||||||
let type_info =
|
let type_info = TypeInfo::Class(ClassTypeInfo::new(class_symbol_id));
|
||||||
TypeInfo::Class(ClassTypeInfo::new(class_symbol_id, constructor_symbol_id));
|
|
||||||
self.state.type_infos.push(type_info);
|
self.state.type_infos.push(type_info);
|
||||||
let type_info_id = self.state.type_infos.len() - 1;
|
let type_info_id = self.state.type_infos.len() - 1;
|
||||||
self.state
|
self.state
|
||||||
@ -458,7 +461,26 @@ impl AnalysisContext {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_by_fqn(&mut self, fqn: &str) -> &TypeInfoId {
|
pub fn error_type(&self) -> TypeInfoId {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn instance_type(&mut self, class_symbol_id: SymbolId) -> TypeInfoId {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn instance_type_by_fqn(&self, fqn: &str) -> TypeInfoId {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_symbol(&self, symbol_id: SymbolId) -> Option<&Symbol> {
|
||||||
|
self.state.symbols.get(symbol_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type_info_for_symbol(&self, symbol_id: SymbolId) -> Option<&TypeInfo> {
|
||||||
|
self.state
|
||||||
|
.symbols_to_type_infos
|
||||||
|
.get(&symbol_id)
|
||||||
|
.and_then(|type_info_id| self.state.type_infos.get(*type_info_id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,8 +57,6 @@ fn get_intrinsic_type(declared_name: &str) -> Option<TypeInfo> {
|
|||||||
match declared_name {
|
match declared_name {
|
||||||
"Any" => Some(TypeInfo::Any),
|
"Any" => Some(TypeInfo::Any),
|
||||||
"Void" => Some(TypeInfo::Void),
|
"Void" => Some(TypeInfo::Void),
|
||||||
"Int" => Some(TypeInfo::Int),
|
|
||||||
"Double" => Some(TypeInfo::Double),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,8 +76,6 @@ fn declared_name_to_type_info(ctx: &AnalysisContext, declared_name: &str) -> Typ
|
|||||||
.expect("Missing core::String from ctx");
|
.expect("Missing core::String from ctx");
|
||||||
ctx.type_infos()[symbol_id].clone()
|
ctx.type_infos()[symbol_id].clone()
|
||||||
}
|
}
|
||||||
"Int" => TypeInfo::Int,
|
|
||||||
"Double" => TypeInfo::Double,
|
|
||||||
"Void" => TypeInfo::Void,
|
"Void" => TypeInfo::Void,
|
||||||
_ => {
|
_ => {
|
||||||
panic!()
|
panic!()
|
||||||
@ -147,10 +143,8 @@ fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
|
|||||||
// todo: fields, methods
|
// todo: fields, methods
|
||||||
|
|
||||||
// Self type constructor
|
// Self type constructor
|
||||||
let type_constructor_type_info = TypeInfo::Class(ClassTypeInfo::new(
|
let type_constructor_type_info =
|
||||||
ctx.nodes_to_symbols()[&class.node_id()],
|
TypeInfo::Class(ClassTypeInfo::new(ctx.nodes_to_symbols()[&class.node_id()]));
|
||||||
constructor_type_info_id,
|
|
||||||
));
|
|
||||||
let type_constructor_type_info_id = ctx.insert_type_info(type_constructor_type_info);
|
let type_constructor_type_info_id = ctx.insert_type_info(type_constructor_type_info);
|
||||||
ctx.associate_node_and_symbol_to_type(class.node_id(), type_constructor_type_info_id);
|
ctx.associate_node_and_symbol_to_type(class.node_id(), type_constructor_type_info_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,10 +150,10 @@ fn resolve_types_expression(
|
|||||||
resolve_types_identifier(identifier, ctx);
|
resolve_types_identifier(identifier, ctx);
|
||||||
}
|
}
|
||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
ctx.insert_type_info_for_node(TypeInfo::Int, integer_literal.node_id());
|
panic!()
|
||||||
}
|
}
|
||||||
Expression::Double(double_literal) => {
|
Expression::Double(double_literal) => {
|
||||||
ctx.insert_type_info_for_node(TypeInfo::Double, double_literal.node_id());
|
panic!()
|
||||||
}
|
}
|
||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
let string_class_symbol_id = ctx
|
let string_class_symbol_id = ctx
|
||||||
|
|||||||
@ -23,7 +23,8 @@ pub fn are_binary_op_compatible(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_number(type_info: &TypeInfo) -> bool {
|
fn is_number(type_info: &TypeInfo) -> bool {
|
||||||
matches!(type_info, TypeInfo::Int | TypeInfo::Double)
|
// matches!(type_info, TypeInfo::Int | TypeInfo::Double)
|
||||||
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn are_numbers(t0: &TypeInfo, t1: &TypeInfo) -> bool {
|
fn are_numbers(t0: &TypeInfo, t1: &TypeInfo) -> bool {
|
||||||
@ -45,7 +46,8 @@ fn is_string(ctx: &AnalysisContext, type_info: &TypeInfo) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn are_ints(t0: &TypeInfo, t1: &TypeInfo) -> bool {
|
fn are_ints(t0: &TypeInfo, t1: &TypeInfo) -> bool {
|
||||||
matches!(t0, TypeInfo::Int) && matches!(t1, TypeInfo::Int)
|
// matches!(t0, TypeInfo::Int) && matches!(t1, TypeInfo::Int)
|
||||||
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binary_op_result(
|
pub fn binary_op_result(
|
||||||
@ -56,7 +58,7 @@ pub fn binary_op_result(
|
|||||||
) -> TypeInfo {
|
) -> TypeInfo {
|
||||||
match op {
|
match op {
|
||||||
BinaryOperation::Multiply => numbers_binary_result(left, right),
|
BinaryOperation::Multiply => numbers_binary_result(left, right),
|
||||||
BinaryOperation::Divide => TypeInfo::Double, // okay for now
|
BinaryOperation::Divide => panic!(), // okay for now
|
||||||
BinaryOperation::Modulo => numbers_binary_result(left, right), // same properties as multiplication
|
BinaryOperation::Modulo => numbers_binary_result(left, right), // same properties as multiplication
|
||||||
BinaryOperation::Add => add_result(ctx, left, right),
|
BinaryOperation::Add => add_result(ctx, left, right),
|
||||||
BinaryOperation::Subtract => numbers_binary_result(left, right),
|
BinaryOperation::Subtract => numbers_binary_result(left, right),
|
||||||
@ -64,23 +66,23 @@ pub fn binary_op_result(
|
|||||||
| BinaryOperation::RightShift
|
| BinaryOperation::RightShift
|
||||||
| BinaryOperation::BitwiseAnd
|
| BinaryOperation::BitwiseAnd
|
||||||
| BinaryOperation::BitwiseXor
|
| BinaryOperation::BitwiseXor
|
||||||
| BinaryOperation::BitwiseOr => TypeInfo::Int,
|
| BinaryOperation::BitwiseOr => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn numbers_binary_result(left: &TypeInfo, right: &TypeInfo) -> TypeInfo {
|
fn numbers_binary_result(left: &TypeInfo, right: &TypeInfo) -> TypeInfo {
|
||||||
match left {
|
match left {
|
||||||
TypeInfo::Int => match right {
|
// TypeInfo::Int => match right {
|
||||||
TypeInfo::Int => TypeInfo::Int,
|
// TypeInfo::Int => TypeInfo::Int,
|
||||||
TypeInfo::Double => TypeInfo::Double,
|
// TypeInfo::Double => TypeInfo::Double,
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
// TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
// _ => panic!(),
|
||||||
},
|
// },
|
||||||
TypeInfo::Double => match right {
|
// TypeInfo::Double => match right {
|
||||||
TypeInfo::Int | TypeInfo::Double => TypeInfo::Double,
|
// TypeInfo::Int | TypeInfo::Double => TypeInfo::Double,
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
// TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
// _ => panic!(),
|
||||||
},
|
// },
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
@ -95,31 +97,31 @@ fn add_result(ctx: &AnalysisContext, left: &TypeInfo, right: &TypeInfo) -> TypeI
|
|||||||
todo!("Adding with non-String, non-number types")
|
todo!("Adding with non-String, non-number types")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeInfo::Int => match right {
|
// TypeInfo::Int => match right {
|
||||||
TypeInfo::Instance(right_instance_type_info) => {
|
// TypeInfo::Instance(right_instance_type_info) => {
|
||||||
if is_string(ctx, right) {
|
// if is_string(ctx, right) {
|
||||||
TypeInfo::Instance(right_instance_type_info.clone())
|
// TypeInfo::Instance(right_instance_type_info.clone())
|
||||||
} else {
|
// } else {
|
||||||
todo!("Adding with non-String, non-number types")
|
// todo!("Adding with non-String, non-number types")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeInfo::Int => TypeInfo::Int,
|
// TypeInfo::Int => TypeInfo::Int,
|
||||||
TypeInfo::Double => TypeInfo::Double,
|
// TypeInfo::Double => TypeInfo::Double,
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
// TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
// _ => panic!(),
|
||||||
},
|
// },
|
||||||
TypeInfo::Double => match right {
|
// TypeInfo::Double => match right {
|
||||||
TypeInfo::Instance(right_instance_type_info) => {
|
// TypeInfo::Instance(right_instance_type_info) => {
|
||||||
if is_string(ctx, right) {
|
// if is_string(ctx, right) {
|
||||||
TypeInfo::Instance(right_instance_type_info.clone())
|
// TypeInfo::Instance(right_instance_type_info.clone())
|
||||||
} else {
|
// } else {
|
||||||
todo!("Adding with non-String, non-number types")
|
// todo!("Adding with non-String, non-number types")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeInfo::Int | TypeInfo::Double => TypeInfo::Double,
|
// // TypeInfo::Int | TypeInfo::Double => TypeInfo::Double,
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
// TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
// _ => panic!(),
|
||||||
},
|
// },
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
@ -128,14 +130,14 @@ fn add_result(ctx: &AnalysisContext, left: &TypeInfo, right: &TypeInfo) -> TypeI
|
|||||||
pub fn can_negate(operand: &TypeInfo) -> bool {
|
pub fn can_negate(operand: &TypeInfo) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
operand,
|
operand,
|
||||||
TypeInfo::Int | TypeInfo::Double | TypeInfo::__Error
|
/* TypeInfo::Int | TypeInfo::Double */ | TypeInfo::__Error
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn negate_result(operand: &TypeInfo) -> TypeInfo {
|
pub fn negate_result(operand: &TypeInfo) -> TypeInfo {
|
||||||
match operand {
|
match operand {
|
||||||
TypeInfo::Int => TypeInfo::Int,
|
// TypeInfo::Int => TypeInfo::Int,
|
||||||
TypeInfo::Double => TypeInfo::Double,
|
// TypeInfo::Double => TypeInfo::Double,
|
||||||
TypeInfo::__Error => TypeInfo::__Error,
|
TypeInfo::__Error => TypeInfo::__Error,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
@ -159,14 +161,14 @@ pub fn can_assign_right_to_left(left: &TypeInfo, right: &TypeInfo, ctx: &Analysi
|
|||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
TypeInfo::Int => match right {
|
// TypeInfo::Int => match right {
|
||||||
TypeInfo::Int => true,
|
// TypeInfo::Int => true,
|
||||||
_ => false,
|
// _ => false,
|
||||||
},
|
// },
|
||||||
TypeInfo::Double => match right {
|
// TypeInfo::Double => match right {
|
||||||
TypeInfo::Double | TypeInfo::Int => true,
|
// TypeInfo::Double | TypeInfo::Int => true,
|
||||||
_ => false,
|
// _ => false,
|
||||||
},
|
// },
|
||||||
TypeInfo::Void => false,
|
TypeInfo::Void => false,
|
||||||
TypeInfo::__Error => true,
|
TypeInfo::__Error => true,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use crate::ast::class::Class;
|
use crate::ast::class::Class;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::type_info::{InstanceTypeInfo, TypeInfo};
|
|
||||||
|
|
||||||
pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
|
pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
|
||||||
for class in compilation_unit.classes() {
|
for class in compilation_unit.classes() {
|
||||||
@ -10,14 +9,10 @@ pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisConte
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
|
fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
|
||||||
let maybe_constructor_type_info_id = class
|
|
||||||
.constructor()
|
|
||||||
.and_then(|constructor| ctx.get_symbol_id(constructor.node_id()));
|
|
||||||
|
|
||||||
let class_symbol_id = ctx.get_symbol_id(class.node_id()).expect(&format!(
|
let class_symbol_id = ctx.get_symbol_id(class.node_id()).expect(&format!(
|
||||||
"Could not find symbol for {} {}",
|
"Could not find symbol for {} {}",
|
||||||
class.node_id(),
|
class.node_id(),
|
||||||
class.declared_name()
|
class.declared_name()
|
||||||
));
|
));
|
||||||
ctx.make_class_type(class_symbol_id, maybe_constructor_type_info_id);
|
ctx.make_class_type(class_symbol_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
57
dmc-lib/src/semantic_analysis/type_analysis/infer/helpers.rs
Normal file
57
dmc-lib/src/semantic_analysis/type_analysis/infer/helpers.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use crate::ast::binary_expression::BinaryOperation;
|
||||||
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
|
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
||||||
|
|
||||||
|
pub fn are_binary_op_compatible(
|
||||||
|
op: &BinaryOperation,
|
||||||
|
lhs: &TypeInfo,
|
||||||
|
rhs: &TypeInfo,
|
||||||
|
ctx: &AnalysisContext,
|
||||||
|
) -> bool {
|
||||||
|
match lhs {
|
||||||
|
TypeInfo::Any
|
||||||
|
| TypeInfo::Class(_)
|
||||||
|
| TypeInfo::Constructor(_)
|
||||||
|
| TypeInfo::Function(_)
|
||||||
|
| TypeInfo::Void => false,
|
||||||
|
TypeInfo::Instance(instance_type_info) => {
|
||||||
|
instance_type_info.is_binary_op_compatible(op, rhs, ctx)
|
||||||
|
}
|
||||||
|
TypeInfo::__Error => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binary_op_result(
|
||||||
|
op: &BinaryOperation,
|
||||||
|
lhs_type_info: &TypeInfo,
|
||||||
|
rhs_type_info: &TypeInfo,
|
||||||
|
ctx: &AnalysisContext,
|
||||||
|
) -> TypeInfoId {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative_op_compatible(operand: &TypeInfo, ctx: &AnalysisContext) -> bool {
|
||||||
|
match operand {
|
||||||
|
TypeInfo::Any
|
||||||
|
| TypeInfo::Class(_)
|
||||||
|
| TypeInfo::Constructor(_)
|
||||||
|
| TypeInfo::Function(_)
|
||||||
|
| TypeInfo::Void => false,
|
||||||
|
TypeInfo::Instance(instance_type_info) => instance_type_info.is_negative_op_compatible(ctx),
|
||||||
|
TypeInfo::__Error => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negative_op_result(operand: &TypeInfo, ctx: &AnalysisContext) -> TypeInfoId {
|
||||||
|
match operand {
|
||||||
|
TypeInfo::Any
|
||||||
|
| TypeInfo::Class(_)
|
||||||
|
| TypeInfo::Constructor(_)
|
||||||
|
| TypeInfo::Function(_)
|
||||||
|
| TypeInfo::Void => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
TypeInfo::Instance(instance_type_info) => instance_type_info.negative_op_result(ctx),
|
||||||
|
TypeInfo::__Error => ctx.error_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
210
dmc-lib/src/semantic_analysis/type_analysis/infer/mod.rs
Normal file
210
dmc-lib/src/semantic_analysis/type_analysis/infer/mod.rs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
pub mod helpers;
|
||||||
|
|
||||||
|
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
|
||||||
|
use crate::ast::call::Call;
|
||||||
|
use crate::ast::class::Class;
|
||||||
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
|
use crate::ast::expression::Expression;
|
||||||
|
use crate::ast::function::Function;
|
||||||
|
use crate::ast::let_statement::LetStatement;
|
||||||
|
use crate::ast::negative_expression::NegativeExpression;
|
||||||
|
use crate::ast::statement::Statement;
|
||||||
|
use crate::diagnostic::{Diagnostic, Diagnostics};
|
||||||
|
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
|
||||||
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
|
use crate::semantic_analysis::analysis_context::helpers::get_name_for_type;
|
||||||
|
use crate::semantic_analysis::type_analysis::infer::helpers::{
|
||||||
|
are_binary_op_compatible, binary_op_result, is_negative_op_compatible, negative_op_result,
|
||||||
|
};
|
||||||
|
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
||||||
|
|
||||||
|
pub fn infer_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) -> Diagnostics {
|
||||||
|
let mut diagnostics = Diagnostics::new();
|
||||||
|
for class in compilation_unit.classes() {
|
||||||
|
infer_types_class(class, ctx, &mut diagnostics);
|
||||||
|
}
|
||||||
|
diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_types_class(class: &Class, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics) {
|
||||||
|
for function in class.functions() {
|
||||||
|
infer_types_function(function, ctx, diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_types_function(
|
||||||
|
function: &Function,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
|
for statement in function.statements() {
|
||||||
|
match statement {
|
||||||
|
Statement::Let(let_statement) => {
|
||||||
|
infer_types_let_statement(let_statement, ctx, diagnostics);
|
||||||
|
}
|
||||||
|
Statement::Expression(expression_statement) => {}
|
||||||
|
Statement::Assign(assign_statement) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_types_let_statement(
|
||||||
|
let_statement: &LetStatement,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
|
let initializer_type = infer_types_expression(let_statement.initializer(), ctx, diagnostics);
|
||||||
|
// todo set symbol's type to the initializer type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_types_expression(
|
||||||
|
expression: &Expression,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) -> TypeInfoId {
|
||||||
|
match expression {
|
||||||
|
Expression::Binary(binary_expression) => {
|
||||||
|
infer_types_binary_expression(binary_expression, ctx, diagnostics)
|
||||||
|
}
|
||||||
|
Expression::Negative(negative_expression) => {
|
||||||
|
resolve_types_negative_expression(negative_expression, ctx, diagnostics)
|
||||||
|
}
|
||||||
|
Expression::Call(call) => resolve_types_call(call, ctx, diagnostics),
|
||||||
|
Expression::Path(path) => {
|
||||||
|
todo!("type of path")
|
||||||
|
}
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
let symbol_id = ctx.get_symbol_id(identifier.node_id()).expect(&format!(
|
||||||
|
"could not get symbol for node_id {}",
|
||||||
|
identifier.node_id()
|
||||||
|
));
|
||||||
|
if let Some(type_info_id) = ctx.get_type_info_id_for_symbol(symbol_id) {
|
||||||
|
type_info_id
|
||||||
|
} else {
|
||||||
|
panic!("could not get type_info_id for symbol_id {}", symbol_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::InstanceSelf(instance_self) => {
|
||||||
|
todo!("type of self (instance self)")
|
||||||
|
}
|
||||||
|
Expression::Integer(_) => ctx.instance_type_by_fqn("core::Int"),
|
||||||
|
Expression::Double(_) => ctx.instance_type_by_fqn("core::Double"),
|
||||||
|
Expression::String(_) => ctx.instance_type_by_fqn("core::String"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_types_binary_expression(
|
||||||
|
binary_expression: &BinaryExpression,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) -> TypeInfoId {
|
||||||
|
let lhs_type_info_id = infer_types_expression(binary_expression.lhs(), ctx, diagnostics);
|
||||||
|
let rhs_type_info_id = infer_types_expression(binary_expression.rhs(), ctx, diagnostics);
|
||||||
|
|
||||||
|
let lhs_type_info = ctx.get_type_info_by_id(lhs_type_info_id);
|
||||||
|
let rhs_type_info = ctx.get_type_info_by_id(rhs_type_info_id);
|
||||||
|
|
||||||
|
let result_type_info_id =
|
||||||
|
if are_binary_op_compatible(binary_expression.op(), lhs_type_info, rhs_type_info, ctx) {
|
||||||
|
binary_op_result(binary_expression.op(), lhs_type_info, rhs_type_info, ctx)
|
||||||
|
} else {
|
||||||
|
let op_name = match binary_expression.op() {
|
||||||
|
BinaryOperation::Multiply => "multiply",
|
||||||
|
BinaryOperation::Divide => "divide",
|
||||||
|
BinaryOperation::Modulo => "modulo",
|
||||||
|
BinaryOperation::Add => "add",
|
||||||
|
BinaryOperation::Subtract => "subtract",
|
||||||
|
BinaryOperation::LeftShift => "left shift",
|
||||||
|
BinaryOperation::RightShift => "right shift",
|
||||||
|
BinaryOperation::BitwiseAnd => "bitwise and",
|
||||||
|
BinaryOperation::BitwiseXor => "bitwise xor",
|
||||||
|
BinaryOperation::BitwiseOr => "bitwise or",
|
||||||
|
};
|
||||||
|
let lhs_type_name = get_name_for_type(lhs_type_info, ctx);
|
||||||
|
let rhs_type_name = get_name_for_type(rhs_type_info, ctx);
|
||||||
|
let message = format!(
|
||||||
|
"Incompatible types: cannot {} {} and {}",
|
||||||
|
op_name, lhs_type_name, rhs_type_name
|
||||||
|
);
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
&message,
|
||||||
|
binary_expression.source_range().start(),
|
||||||
|
binary_expression.source_range().end(),
|
||||||
|
)
|
||||||
|
.with_error_code(BINARY_INCOMPATIBLE_TYPES);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
|
||||||
|
ctx.error_type()
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.associate_node_to_type(binary_expression.node_id(), result_type_info_id);
|
||||||
|
|
||||||
|
result_type_info_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_types_negative_expression(
|
||||||
|
negative_expression: &NegativeExpression,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) -> TypeInfoId {
|
||||||
|
let operand_type_info_id =
|
||||||
|
infer_types_expression(negative_expression.operand(), ctx, diagnostics);
|
||||||
|
let operand_type_info = ctx.get_type_info_by_id(operand_type_info_id);
|
||||||
|
let result_type_info_id = if is_negative_op_compatible(operand_type_info, ctx) {
|
||||||
|
negative_op_result(operand_type_info, ctx)
|
||||||
|
} else {
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
&format!(
|
||||||
|
"Cannot negate operand of type {}",
|
||||||
|
get_name_for_type(operand_type_info, ctx)
|
||||||
|
),
|
||||||
|
negative_expression.source_range().start(),
|
||||||
|
negative_expression.source_range().end(),
|
||||||
|
);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
ctx.error_type()
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.associate_node_to_type(negative_expression.node_id(), operand_type_info_id);
|
||||||
|
|
||||||
|
result_type_info_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_types_call(
|
||||||
|
call: &Call,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) -> TypeInfoId {
|
||||||
|
let receiver_type_info_id = infer_types_expression(call.callee(), ctx, diagnostics);
|
||||||
|
let receiver_type_info = ctx.get_type_info_by_id(receiver_type_info_id);
|
||||||
|
match receiver_type_info {
|
||||||
|
TypeInfo::Any | TypeInfo::Void => {
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
&format!(
|
||||||
|
"Cannot call receiver of type {}",
|
||||||
|
match receiver_type_info {
|
||||||
|
TypeInfo::Any => "Any",
|
||||||
|
TypeInfo::Void => "Void",
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
call.source_range().start(),
|
||||||
|
call.source_range().end(),
|
||||||
|
);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
ctx.error_type()
|
||||||
|
}
|
||||||
|
TypeInfo::Class(class_type_info) => {
|
||||||
|
let symbol = class_type_info.class_symbol_id();
|
||||||
|
ctx.instance_type(symbol)
|
||||||
|
}
|
||||||
|
TypeInfo::Constructor(_) => {
|
||||||
|
panic!("Cannot infer expression type directly on ConstructorTypeInfo");
|
||||||
|
}
|
||||||
|
TypeInfo::Function(function_type_info) => function_type_info.return_type_id(),
|
||||||
|
TypeInfo::Instance(_) => {
|
||||||
|
unimplemented!("Calling instances of objects not yet supported.")
|
||||||
|
}
|
||||||
|
TypeInfo::__Error => ctx.error_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,19 @@
|
|||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::type_analysis::collect::collect_types;
|
use crate::semantic_analysis::type_analysis::collect::collect_types;
|
||||||
|
use crate::semantic_analysis::type_analysis::infer::infer_types;
|
||||||
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
|
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
|
||||||
|
|
||||||
mod collect;
|
mod collect;
|
||||||
mod infer;
|
mod infer;
|
||||||
mod resolve;
|
mod resolve;
|
||||||
|
|
||||||
pub fn analyze_types(compilation_unit: &CompilationUnit, analysis_context: &mut AnalysisContext) {
|
pub fn analyze_types(
|
||||||
|
compilation_unit: &CompilationUnit,
|
||||||
|
analysis_context: &mut AnalysisContext,
|
||||||
|
) -> Diagnostics {
|
||||||
collect_types(compilation_unit, analysis_context);
|
collect_types(compilation_unit, analysis_context);
|
||||||
resolve_types(compilation_unit, analysis_context);
|
resolve_types(compilation_unit, analysis_context);
|
||||||
|
infer_types(compilation_unit, analysis_context)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
|
use crate::ast::binary_expression::BinaryOperation;
|
||||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::symbol::SymbolId;
|
use crate::semantic_analysis::symbol::{ClassSymbol, SymbolId};
|
||||||
|
|
||||||
pub type TypeInfoId = usize;
|
pub type TypeInfoId = usize;
|
||||||
|
|
||||||
@ -10,8 +11,6 @@ pub enum TypeInfo {
|
|||||||
Constructor(ConstructorTypeInfo),
|
Constructor(ConstructorTypeInfo),
|
||||||
Function(FunctionTypeInfo),
|
Function(FunctionTypeInfo),
|
||||||
Instance(InstanceTypeInfo),
|
Instance(InstanceTypeInfo),
|
||||||
Int,
|
|
||||||
Double,
|
|
||||||
Void,
|
Void,
|
||||||
__Error,
|
__Error,
|
||||||
}
|
}
|
||||||
@ -23,13 +22,6 @@ impl TypeInfo {
|
|||||||
_ => panic!("Attempt to unwrap {:?} as Constructor", self),
|
_ => panic!("Attempt to unwrap {:?} as Constructor", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_class(&self) -> &ClassTypeInfo {
|
|
||||||
match self {
|
|
||||||
TypeInfo::Class(type_constructor_info) => type_constructor_info,
|
|
||||||
_ => panic!("Attempt to unwrap {:?} as TypeConstructor", self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -91,24 +83,16 @@ impl ConstructorTypeInfo {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ClassTypeInfo {
|
pub struct ClassTypeInfo {
|
||||||
class_symbol_id: SymbolId,
|
class_symbol_id: SymbolId,
|
||||||
constructor_symbol_id: Option<SymbolId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassTypeInfo {
|
impl ClassTypeInfo {
|
||||||
pub fn new(class_symbol_id: SymbolId, constructor_symbol_id: Option<SymbolId>) -> Self {
|
pub fn new(class_symbol_id: SymbolId) -> Self {
|
||||||
Self {
|
Self { class_symbol_id }
|
||||||
class_symbol_id,
|
|
||||||
constructor_symbol_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_symbol_id(&self) -> SymbolId {
|
pub fn class_symbol_id(&self) -> SymbolId {
|
||||||
self.class_symbol_id
|
self.class_symbol_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constructor_type_info_id(&self) -> Option<SymbolId> {
|
|
||||||
self.constructor_symbol_id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -130,4 +114,94 @@ impl InstanceTypeInfo {
|
|||||||
let right_class_symbol = ctx.symbols()[right.class_symbol_id].unwrap_class_symbol();
|
let right_class_symbol = ctx.symbols()[right.class_symbol_id].unwrap_class_symbol();
|
||||||
self_class_symbol.can_assign_from(right_class_symbol, ctx)
|
self_class_symbol.can_assign_from(right_class_symbol, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_self_class_symbol<'a>(&self, ctx: &'a AnalysisContext) -> &'a ClassSymbol {
|
||||||
|
ctx.get_symbol(self.class_symbol_id)
|
||||||
|
.expect(&format!(
|
||||||
|
"self_class_symbol {} not found",
|
||||||
|
self.class_symbol_id
|
||||||
|
))
|
||||||
|
.unwrap_class_symbol()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_binary_op_compatible(
|
||||||
|
&self,
|
||||||
|
op: &BinaryOperation,
|
||||||
|
right: &TypeInfo,
|
||||||
|
ctx: &AnalysisContext,
|
||||||
|
) -> bool {
|
||||||
|
match right {
|
||||||
|
TypeInfo::Any
|
||||||
|
| TypeInfo::Class(_)
|
||||||
|
| TypeInfo::Constructor(_)
|
||||||
|
| TypeInfo::Function(_)
|
||||||
|
| TypeInfo::Void => false,
|
||||||
|
TypeInfo::Instance(right_instance_type_info) => {
|
||||||
|
// this is all just filler until we have proper traits and classes
|
||||||
|
let right_fqn = right_instance_type_info.get_self_class_symbol(ctx).fqn();
|
||||||
|
match self.get_self_class_symbol(ctx).fqn() {
|
||||||
|
"core::String" => {
|
||||||
|
if let BinaryOperation::Add = op {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"core::Int" => match op {
|
||||||
|
BinaryOperation::Add => true,
|
||||||
|
BinaryOperation::Multiply
|
||||||
|
| BinaryOperation::Divide
|
||||||
|
| BinaryOperation::Modulo
|
||||||
|
| BinaryOperation::Subtract => match right_fqn {
|
||||||
|
"core::Int" | "core::Double" => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
BinaryOperation::LeftShift
|
||||||
|
| BinaryOperation::RightShift
|
||||||
|
| BinaryOperation::BitwiseAnd
|
||||||
|
| BinaryOperation::BitwiseXor
|
||||||
|
| BinaryOperation::BitwiseOr => match right_fqn {
|
||||||
|
"core::Int" => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"core::Double" => match op {
|
||||||
|
BinaryOperation::Add => true,
|
||||||
|
BinaryOperation::Multiply
|
||||||
|
| BinaryOperation::Divide
|
||||||
|
| BinaryOperation::Modulo
|
||||||
|
| BinaryOperation::Subtract => match right_fqn {
|
||||||
|
"core::Int" => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
BinaryOperation::LeftShift
|
||||||
|
| BinaryOperation::RightShift
|
||||||
|
| BinaryOperation::BitwiseAnd
|
||||||
|
| BinaryOperation::BitwiseXor
|
||||||
|
| BinaryOperation::BitwiseOr => false,
|
||||||
|
},
|
||||||
|
_ => panic!("unknown type: {}", self.get_self_class_symbol(ctx).fqn()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeInfo::__Error => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative_op_compatible(&self, ctx: &AnalysisContext) -> bool {
|
||||||
|
match self.get_self_class_symbol(ctx).fqn() {
|
||||||
|
"core::Int" | "core::Double" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negative_op_result(&self, ctx: &AnalysisContext) -> TypeInfoId {
|
||||||
|
match self.get_self_class_symbol(ctx).fqn() {
|
||||||
|
"core::Int" => ctx.instance_type_by_fqn("core::Int"),
|
||||||
|
"core::Double" => ctx.instance_type_by_fqn("core::Double"),
|
||||||
|
_ => panic!(
|
||||||
|
"unknown negatable type: {}",
|
||||||
|
self.get_self_class_symbol(ctx).fqn()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user