implementation module type_io_equal_type_defs

import StdEnv,StdMaybe,StdDynamicTypes
from containers import equal_strictness_lists
import type_io_read
import typetable

:: OrderedTypeRef
	= {	otr_type_ref1	:: TypeTableTypeReference
	,	otr_type_ref2	:: TypeTableTypeReference
	};

:: *EqTypesState
	= {	ets_within_type_table			:: !Bool	// iff ets_left_i == ets_right_i
	,	ets_left_i						:: !Int		// type table index for left type (1st arg)
	,	ets_right_i						:: !Int		// type table index for right type (2nd arg)
	,	ets_left_module_i				:: !Int		// left module index
	,	ets_right_module_i				:: !Int		// right module index
	,	ets_assumed_type_equivalences	:: [OrderedTypeRef]
	,	ets_proven_type_equivalences	:: [OrderedTypeRef]
	,	ets_left_string_table			:: !String
	,	ets_right_string_table			:: !String
	}; 
	
default_eq_types_state :: *EqTypesState;
default_eq_types_state
	= { ets_within_type_table			= False
	,	ets_left_i						= -1
	,	ets_right_i						= -1
	,	ets_left_module_i				= -1
	,	ets_right_module_i				= -1
	,	ets_assumed_type_equivalences	= []
	,	ets_proven_type_equivalences	= []
	,	ets_left_string_table			= {}
	,	ets_right_string_table			= {}
	}; 
	
find_type_equivalence ordered_type_ref ets=:{ets_assumed_type_equivalences,ets_proven_type_equivalences}
	# ets_assumed_type_equivalent
		= filter ((==) ordered_type_ref) ets_assumed_type_equivalences
	# ets_proven_type_equivalent
		= filter ((==) ordered_type_ref) ets_proven_type_equivalences
	# found
		= not (isEmpty ets_assumed_type_equivalent) || not (isEmpty ets_proven_type_equivalent)
	= (found,ets)

assume_type_equivalence ordered_type_ref ets=:{ets_assumed_type_equivalences}
	= {ets & ets_assumed_type_equivalences = [ordered_type_ref:ets_assumed_type_equivalences] } 
	
get_assumed_type_equivalence ets=:{ets_assumed_type_equivalences=[assumed_type_equivalence:ets_assumed_type_equivalences]}
	# ets = {ets & ets_assumed_type_equivalences = ets_assumed_type_equivalences}
	= (assumed_type_equivalence,ets)

enter_proven_assumption proven_type_equivalence ets=:{ets_proven_type_equivalences}
	= {ets & ets_proven_type_equivalences = [proven_type_equivalence:ets_proven_type_equivalences]}

// type_table1 <> type_table2 otherwise it would be within a type table. it suffices for nf
order_type_ref type_ref1=:(TypeTableTypeReference type_table1 tio_type_ref1) type_ref2=:(TypeTableTypeReference type_table2 tio_type_ref2)
	| type_table1 < type_table2
		= {otr_type_ref1 = type_ref1,otr_type_ref2 = type_ref2}
		| type_table1 > type_table2
			= {otr_type_ref1 = type_ref2,otr_type_ref2 = type_ref1};
			= order_tio_type_reference tio_type_ref1 tio_type_ref2;
where
	order_tio_type_reference {tio_type_without_definition=Just _} {tio_type_without_definition=Just _}
		= {otr_type_ref1 = type_ref1,otr_type_ref2 = type_ref2};
	order_tio_type_reference t1=:{tio_tr_module_n=tio_tr_module_n1,tio_tr_type_def_n=tio_tr_type_def_n1} t2=:{tio_tr_module_n=tio_tr_module_n2,tio_tr_type_def_n=tio_tr_type_def_n2}
		| tio_tr_module_n1 < tio_tr_module_n2
			= {otr_type_ref1 = type_ref1,otr_type_ref2 = type_ref2};
			|  tio_tr_module_n1 > tio_tr_module_n2
				= {otr_type_ref1 = type_ref2,otr_type_ref2 = type_ref1};
				| tio_tr_type_def_n1 < tio_tr_type_def_n2
					= {otr_type_ref1 = type_ref1,otr_type_ref2 = type_ref2};
					| tio_tr_type_def_n1 > tio_tr_type_def_n2
						= {otr_type_ref1 = type_ref2,otr_type_ref2 = type_ref1};
						= {otr_type_ref1 = type_ref1,otr_type_ref2 = type_ref2};

instance == OrderedTypeRef
where
	(==) ordered_type_refA ordered_type_refB
		= ordered_type_refA.otr_type_ref1 == ordered_type_refB.otr_type_ref1 &&
		  ordered_type_refA.otr_type_ref2 == ordered_type_refB.otr_type_ref2
			
// Properties:
// - the order of type tables is maintained. 1st arg b
class EqTypesExtended a
where
	equal_type_defs :: !a !a !{#*TypeTable} !*EqTypesState -> (!Bool,!{#*TypeTable},!*EqTypesState)

// only externally called
instance EqTypesExtended TypeTableTypeReference
where 
	equal_type_defs pt1=:(TypeTableTypeReference _ {tio_type_without_definition=Just type_name1}) pt2=:(TypeTableTypeReference _ {tio_type_without_definition=Just type_name2}) type_tables ets
		= (type_name1 == type_name2,type_tables,ets)

	equal_type_defs type_ref1=:(TypeTableTypeReference type_table1 type_reference1=:{tio_type_without_definition=Nothing}) type_ref2=:(TypeTableTypeReference type_table2 type_reference2=:{tio_type_without_definition=Nothing}) type_tables ets
		| type_ref1 == type_ref2
			= (True,type_tables,ets)

		# ets_within_type_table = type_table1 == type_table2
			
		// select {left,right} string tables
		# (ets_left_string_table,type_tables)
			= type_tables![type_table1].tt_type_io_state.tis_string_table
		# (ets_right_string_table,type_tables)
			= type_tables![type_table2].tt_type_io_state.tis_string_table

		# ets = { ets
			&	ets_within_type_table	= ets_within_type_table
			,	ets_left_i				= type_table1
			,	ets_right_i				= type_table2
			,	ets_left_string_table	= if ets_within_type_table {} ets_left_string_table
			,	ets_right_string_table	= if ets_within_type_table {} ets_right_string_table
			}; 
		= equal_type_defs type_reference1 type_reference2 type_tables ets
		
	equal_type_defs _ _ type_tables ets
		= (False,type_tables,ets)

class DerefTypeReference a
where
	deref_type_reference :: a !{#TypeTable} -> (TIO_CheckedTypeDef,!{#TypeTable})

instance DerefTypeReference TypeTableTypeReference
where
	deref_type_reference type1=:(TypeTableTypeReference type_table_i type=:{tio_tr_module_n,tio_tr_type_def_n,tio_type_without_definition=Nothing}) type_tables
		| type_table_i<0 || type_table_i>=size type_tables
			= abort ("deref_type_reference: invalid type table reference " +++ toString type_table_i +++ " - " +++ toString (size type_tables))
		= type_tables![type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n]

// types within one type table and types across type tables
instance EqTypesExtended TIO_TypeReference
where
	equal_type_defs type_ref1a=:{tio_tr_module_n=tio_tr_module_n1} type_ref2a=:{tio_tr_module_n=tio_tr_module_n2} type_tables ets=:{/*ets_within_type_table=False,*/ets_left_module_i,ets_right_module_i,ets_left_i,ets_right_i}
		# type_ref1 = TypeTableTypeReference ets_left_i type_ref1a
		# type_ref2 = TypeTableTypeReference ets_right_i type_ref2a
		
		| type_ref1 == type_ref2
			= (True,type_tables,ets)

			// check whether type pair is assumed or proven to be equivalent
			# ordered_type_ref
				= order_type_ref type_ref1 type_ref2
			# (are_types_equivalent,ets)
				= find_type_equivalence ordered_type_ref ets
			| are_types_equivalent
				= (True,type_tables,ets)
	
				// assume type equivalence (termination)
				# ets = assume_type_equivalence ordered_type_ref ets
	
				// dereference type reference
				# (type1,type_tables)
					= deref_type_reference type_ref1 type_tables
				# (type2,type_tables )
					= deref_type_reference type_ref2 type_tables
										
				// set defining modules of new types
				# ets = { ets & ets_left_module_i = tio_tr_module_n1, ets_right_module_i = tio_tr_module_n2 }
					
				// check it
				# (is_type_pair_equivalent,type_tables,ets)
					= equal_type_defs type1 type2 type_tables ets
	
				// restore old defining modules
				# ets = { ets & ets_left_module_i = ets_left_module_i, ets_right_module_i = ets_right_module_i }

				# (assumed_type_equivalence,ets)
					= get_assumed_type_equivalence ets
				| is_type_pair_equivalent
					// assumption has been proven
					# ets = enter_proven_assumption assumed_type_equivalence ets				
					= (True,type_tables,ets)
	
					= (False,type_tables,ets)
					
	equal_type_defs t1 t2 type_tables ets
		= abort "equal_type_defs; internal error";

instance EqTypesExtended (TIO_TypeDef a) | EqTypesExtended a
where
	equal_type_defs {tio_td_name=tio_td_name1,tio_td_arity=tio_td_arity1,tio_td_rhs=tio_td_rhs1} 
				{tio_td_name=tio_td_name2,tio_td_arity=tio_td_arity2,tio_td_rhs=tio_td_rhs2} type_tables ets=:{ets_within_type_table,ets_left_string_table,ets_right_string_table}
		# tio_td_name
			= if ets_within_type_table (tio_td_name1 == tio_td_name2) (get_name_from_string_table tio_td_name1 ets_left_string_table == get_name_from_string_table tio_td_name2 ets_right_string_table)
		| tio_td_name && tio_td_arity1 == tio_td_arity2
			= equal_type_defs tio_td_rhs1 tio_td_rhs2 type_tables ets
			= (False,type_tables,ets)
	
instance EqTypesExtended TIO_TypeRhs
where
	equal_type_defs (TIO_AlgType tio_defined_symbols1) (TIO_AlgType tio_defined_symbols2) type_tables ets
		= equal_type_defs tio_defined_symbols1 tio_defined_symbols2 type_tables ets;
	equal_type_defs (TIO_RecordType tio_record_type1) (TIO_RecordType tio_record_type2) type_tables ets
		= equal_type_defs tio_record_type1 tio_record_type2 type_tables ets;
	equal_type_defs (TIO_GenericDictionaryType tio_record_type1) (TIO_GenericDictionaryType tio_record_type2) type_tables ets
		= equal_type_defs tio_record_type1 tio_record_type2 type_tables ets;
	equal_type_defs TIO_UnknownType TIO_UnknownType type_tables ets
		= abort "UnknownType";
	equal_type_defs (TIO_SynType syn_type1) (TIO_SynType syn_type2) type_tables ets
		= equal_type_defs syn_type1 syn_type2 type_tables ets;
	equal_type_defs _ _ type_tables ets
		= (False,type_tables,ets)

instance EqTypesExtended TIO_ConstructorSymbol
where
	equal_type_defs {tio_cons=tio_cons1} {tio_cons=tio_cons2} type_tables ets
		=	equal_type_defs tio_cons1 tio_cons2 type_tables ets

instance EqTypesExtended TIO_RecordType
where
	equal_type_defs {tio_rt_fields=tio_rt_fields1,tio_rt_constructor=tio_rt_constructor1} {tio_rt_fields=tio_rt_fields2,tio_rt_constructor=tio_rt_constructor2} type_tables ets
		# (fields_eq,type_tables,ets) = equal_type_defs tio_rt_fields1 tio_rt_fields2 type_tables ets
		| fields_eq
			= equal_type_defs tio_rt_constructor1 tio_rt_constructor2 type_tables ets
			= (False,type_tables,ets)

instance EqTypesExtended TIO_DefinedSymbol
where
	equal_type_defs {tio_ds_ident=tio_ds_ident1,tio_ds_arity=tio_ds_arity1,tio_ds_index=tio_ds_index1} {tio_ds_ident=tio_ds_ident2,tio_ds_arity=tio_ds_arity2,tio_ds_index=tio_ds_index2} 
			type_tables ets=:{ets_within_type_table,ets_left_string_table,ets_right_string_table,ets_left_i,ets_right_i,ets_left_module_i,ets_right_module_i}
		# tio_ds_ident
			= if ets_within_type_table (tio_ds_ident1 == tio_ds_ident2) 
				(get_name_from_string_table tio_ds_ident1 ets_left_string_table == get_name_from_string_table tio_ds_ident2 ets_right_string_table)
		| tio_ds_ident && tio_ds_arity1 == tio_ds_arity2 
			# (tio_cons_symb1,type_tables)
				= type_tables![ets_left_i].tt_tio_common_defs.[ets_left_module_i].tio_com_cons_defs.[tio_ds_index1];
			# (tio_cons_symb2,type_tables)
				= type_tables![ets_right_i].tt_tio_common_defs.[ets_right_module_i].tio_com_cons_defs.[tio_ds_index2];
			= equal_type_defs tio_cons_symb1 tio_cons_symb2 type_tables ets;			
			= (False,type_tables,ets);
	equal_type_defs _ _ type_tables ets
		= abort "instance EqTypesExtended TIO_DefinedSymbol";

instance EqTypesExtended TIO_ConsDef
where
	equal_type_defs {tio_cons_symb=tio_cons_symb1,tio_cons_type=tio_cons_type1,tio_cons_exi_vars=tio_cons_exi_vars1} 
				{tio_cons_symb=tio_cons_symb2,tio_cons_type=tio_cons_type2,tio_cons_exi_vars=tio_cons_exi_vars2} type_tables ets=:{ets_within_type_table,ets_left_string_table,ets_right_string_table}
		# tio_cons_symb
			= if ets_within_type_table (tio_cons_symb1 == tio_cons_symb2) (get_name_from_string_table tio_cons_symb1 ets_left_string_table == get_name_from_string_table tio_cons_symb2 ets_right_string_table)
		| tio_cons_symb
			// constructors are equally named
			= equal_type_defs tio_cons_type1 tio_cons_type2 type_tables ets
			= (False,type_tables,ets);

instance EqTypesExtended TIO_SymbolType
where
	equal_type_defs {tio_st_vars=tio_st_vars1,tio_st_args=tio_st_args1,tio_st_arity=tio_st_arity1,tio_st_result=tio_st_result1,tio_st_args_strictness=tio_st_args_strictness1}
				{tio_st_vars=tio_st_vars2,tio_st_args=tio_st_args2,tio_st_arity=tio_st_arity2,tio_st_result=tio_st_result2,tio_st_args_strictness=tio_st_args_strictness2} type_tables ets
		| tio_st_arity1 == tio_st_arity2 && equal_strictness_lists tio_st_args_strictness1 tio_st_args_strictness2
			# (are_st_vars_equal,type_tables,ets)
				= equal_type_defs tio_st_vars1 tio_st_vars2 type_tables ets;
			| are_st_vars_equal
				# (are_st_args_equal,type_tables,ets)
					= equal_type_defs tio_st_args1 tio_st_args2 type_tables ets;
				| are_st_args_equal
					= equal_type_defs tio_st_result1 tio_st_result2 type_tables ets;
					// tio_st_args1 <> tio_st_args2
					= (False,type_tables,ets) 
				// tio_st_vars1 <> tio_st_vars2
				= (False,type_tables,ets)
			// tio_st_arity1 <> tio_st_arity2
			= (False,type_tables,ets)
			
	equal_type_defs _ _ type_tables ets
		= abort "instance EqTypesExtended TIO_SymbolType";

instance EqTypesExtended TIO_AType
where
	equal_type_defs {tio_at_type=tio_at_type1} {tio_at_type=tio_at_type2} type_tables ets
		= equal_type_defs tio_at_type1 tio_at_type2 type_tables ets;
			
instance EqTypesExtended TIO_Type
where
	equal_type_defs (TIO_TAS tio_type_symb_ident1 tio_atypes1 strictness1) (TIO_TAS tio_type_symb_ident2 tio_atypes2 strictness2) type_tables ets
		# (are_type_symb_idents_equal,type_tables,ets)
			= equal_type_defs tio_type_symb_ident1 tio_type_symb_ident2 type_tables ets;
		| are_type_symb_idents_equal && equal_strictness_lists strictness1 strictness2
			= equal_type_defs tio_atypes1 tio_atypes2 type_tables ets;
			= (False,type_tables,ets);
	equal_type_defs (tio_atype1a ----> tio_atype1b) (tio_atype2a ----> tio_atype2b) type_tables ets
		# (are_atypes1_equal,type_tables,ets)
			= equal_type_defs tio_atype1a tio_atype2a type_tables ets;
		| are_atypes1_equal
			= equal_type_defs tio_atype1b tio_atype2b type_tables ets;
			= (False,type_tables,ets);
	equal_type_defs (tio_cons_variable1 :@@: tio_atypes1) (tio_cons_variable2 :@@: tio_atypes2) type_tables ets
		# (are_tio_cons_variables_equal,type_tables,ets)
			= equal_type_defs tio_cons_variable1 tio_cons_variable2 type_tables ets;
		| are_tio_cons_variables_equal
			= equal_type_defs tio_atypes1 tio_atypes2 type_tables ets;
			= (False,type_tables,ets);
	equal_type_defs (TIO_TB tio_basic_type1) (TIO_TB tio_basic_type2) type_tables ets
		= equal_type_defs tio_basic_type1 tio_basic_type2 type_tables ets;
	equal_type_defs (TIO_GTV tio_type_var1) (TIO_GTV tio_type_var2) type_tables ets
		= equal_type_defs tio_type_var1 tio_type_var2 type_tables ets;
	equal_type_defs (TIO_TV tio_type_var1) (TIO_TV tio_type_var2) type_tables ets
		= equal_type_defs tio_type_var1 tio_type_var2 type_tables ets;
	equal_type_defs (TIO_TQV tio_type_var1) (TIO_TQV tio_type_var2) type_tables ets
		= equal_type_defs tio_type_var1 tio_type_var2 type_tables ets;
	equal_type_defs (TIO_GenericFunction kind1 tio_symbol_type1) (TIO_GenericFunction kind2 tio_symbol_type2) type_tables ets
		| kind1==kind2
			= equal_type_defs tio_symbol_type1 tio_symbol_type2 type_tables ets
			= (False,type_tables,ets);
	equal_type_defs TIO_TE TIO_TE type_tables ets
		= (True,type_tables,ets);
	equal_type_defs _ _ type_tables ets
		= (False,type_tables,ets);
		
instance EqTypesExtended TIO_BasicType
where
	equal_type_defs TIO_BT_Int TIO_BT_Int type_tables ets
		= (True,type_tables,ets)
	equal_type_defs TIO_BT_Char TIO_BT_Char type_tables ets
		= (True,type_tables,ets)
	equal_type_defs TIO_BT_Real TIO_BT_Real type_tables ets
		= (True,type_tables,ets)
	equal_type_defs TIO_BT_Bool TIO_BT_Bool type_tables ets
		= (True,type_tables,ets)
	equal_type_defs TIO_BT_Dynamic TIO_BT_Dynamic type_tables ets
		= (True,type_tables,ets)
	equal_type_defs TIO_BT_File TIO_BT_File type_tables ets
		= (True,type_tables,ets)
	equal_type_defs TIO_BT_World TIO_BT_World type_tables ets
		= (True,type_tables,ets)
	equal_type_defs (TIO_BT_String tio_type1) (TIO_BT_String tio_type2) type_tables ets
		= equal_type_defs tio_type1 tio_type2 type_tables ets;
	equal_type_defs _ _ type_tables ets
		= (False,type_tables,ets);
		
instance EqTypesExtended TIO_ConsVariable
where
	equal_type_defs (TIO_CV tio_type_var1) (TIO_CV tio_type_var2) type_tables ets
		= equal_type_defs tio_type_var1 tio_type_var2 type_tables ets;
	equal_type_defs (TIO_TempCV _) (TIO_TempCV _) type_tables ets
		= abort "instance equal_type_defs TIO_ConsVariable; TIO_TempCV";
	equal_type_defs (TIO_TempQCV _) (TIO_TempQCV _) type_tables ets
		= abort "instance equal_type_defs TIO_ConsVariable; TIO_TempQCV";
	equal_type_defs _ _ type_tables ets
		= (False,type_tables,ets);

instance EqTypesExtended TIO_TypeSymbIdent
where
	equal_type_defs {tio_type_name_ref=tio_type_name_ref1,tio_type_arity=tio_type_arity1} {tio_type_name_ref=tio_type_name_ref2,tio_type_arity=tio_type_arity2} type_tables ets
		| tio_type_arity1 == tio_type_arity2
			= equal_type_defs tio_type_name_ref1 tio_type_name_ref2 type_tables ets;
			= (False,type_tables,ets);

instance EqTypesExtended TIO_ATypeVar
where
	equal_type_defs {tio_atv_variable=tio_atv_variable1} {tio_atv_variable=tio_atv_variable2} type_tables ets
		= equal_type_defs tio_atv_variable1 tio_atv_variable2 type_tables ets;

instance EqTypesExtended TIO_TypeVar
where
	equal_type_defs {tio_tv_name=tio_tv_name1} {tio_tv_name=tio_tv_name2} type_tables ets=:{ets_within_type_table,ets_left_string_table,ets_right_string_table}
		= (tio_tv_name1 == tio_tv_name2,type_tables,ets)
		
instance EqTypesExtended TIO_FieldSymbol
where
	equal_type_defs {tio_fs_name=tio_fs_name1} {tio_fs_name=tio_fs_name2} type_tables 
				ets=:{ets_within_type_table,ets_left_string_table,ets_right_string_table}
		# w1 = get_name_from_string_table tio_fs_name1 ets_left_string_table;
		# w2 = get_name_from_string_table tio_fs_name2 ets_right_string_table;
		# tio_fs_name_eq = if ets_within_type_table
							(tio_fs_name1 == tio_fs_name2)
							(w1 == w2);
		= (tio_fs_name_eq,type_tables,ets);

instance EqTypesExtended [a] | EqTypesExtended a
where
	equal_type_defs [] [] tio_common_defs type_io_state
		= (True,tio_common_defs,type_io_state);
	equal_type_defs [type1:types1] [type2:types2] tio_common_defs type_io_state
		# (type1_equals_type2,tio_common_defs,type_io_state)
			= equal_type_defs type1 type2 tio_common_defs type_io_state;
		| not type1_equals_type2
			= (False,tio_common_defs,type_io_state);
		= equal_type_defs types1 types2 tio_common_defs type_io_state;
	equal_type_defs _ _ tio_common_defs type_io_state
		= (False,tio_common_defs,type_io_state);
			
instance EqTypesExtended {#a} | Array {#} a & EqTypesExtended a
where
	equal_type_defs a1 a2 type_tables ets
		| s_a1 <> s_a2
			= (False,type_tables,ets)
		= equal_type_defs_loop 0 s_a1 type_tables ets
	where 
		equal_type_defs_loop i limit type_tables ets
			| i == limit
				= (True,type_tables,ets)
			# (elements_are_equal,type_tables,ets)
				= equal_type_defs a1.[i] a2.[i] type_tables ets;
			| not elements_are_equal
				= (False,type_tables,ets);
			= equal_type_defs_loop (inc i) limit type_tables ets;

		s_a1 = size a1
		s_a2 = size a2
