implementation module Request;

// for apply
USE_OLD_NAMESTABLE_STORAGE yes no :== no;

import StdEnv;
import StdDynamicError;
import DLState;
import CommonObjectToDisk; // mac
import ReadState;

import ObjectToMem;

import pdObjectToMem;
import DynamicLink;

// utilities
import ExtInt;
import ExtFile;

// utilities; power mac interface
//from files import LaunchApplication; //, FSMakeFSSpec;
//import ioState;
//import files; 

//1.3
from deltaIOState import FileEnv;
from ReadObject import ImportDynamicLibrarySymbols;
//3.1
/*2.0
from ReadObject import class ImportDynamicLibrarySymbols(..), instance ImportDynamicLibrarySymbols LibraryList;
from deltaIOState import class FileEnv, instance FileEnv (IOState s);
// instance GetTypeTableIndex LibraryID
0.2*/

import deltaEventIO;
import Redirections;
from utilities import foldSt;
import StdMaybe;
import MemoryState;
from type_io_common import PredefinedModuleName;
import utilities;
import CollectTypes;
from predef import UnderscoreSystemDynamicModule_String, DynamicRepresentation_String;
import predefined_types;
from type_io_common import UnderscoreSystemModule;
from ExtList import anySt, allSt;

instance FileSystem (IOState s)
where {
	fopen a0 a1 io
		#! ((r0,r1),io)
			= accFiles fopen2 io;
		= (r0,r1,io);
	where {
		fopen2 files
			# (r0,r1,files)
				= fopen a0 a1 files;
			= ((r0,r1),files);
	} // fopen
	
	fclose file io
		= accFiles (fclose file) io; 
	
	stdio io
		= accFiles stdio io;
	sfopen a0 a1 io
		#! ((r0,r1),io)
			= accFiles fopen2 io;
		= (r0,r1,io);
	where {
		fopen2 files
			# (r0,r1,files)
				= sfopen a0 a1 files;
			= ((r0,r1),files);
	} // sfopen

};
/*
class FileSystem f where
	fopen :: !{#Char} !Int !*f -> (!Bool,!*File,!*f)
			/*	Opens a file for the first time in a certain mode (read, write or append, text or data).
				The boolean output parameter reports success or failure. */
	fclose :: !*File !*f -> (!Bool,!*f)
			/* Closes a file */
	stdio  :: !*f -> (!*File,!*f)
			/*	Open the 'Console' for reading and writing. */
	sfopen :: !{#Char} !Int !*f -> (!Bool,!File,!*f)
			/*	With sfopen a file can be opened for reading more than once.
				On a file opened by sfopen only the operations beginning with sf can be used.
				The sf... operations work just like the corresponding f... operations.
				They can't be used for files opened with fopen or freopen. */

instance FileSystem Files
instance FileSystem World

class FileEnv env where
	accFiles :: !.(*Files -> (.x,*Files)) !*env -> (!.x,!*env)
	appFiles :: !.(*Files -> *Files) !*env -> *env
*/

// IO 0.8.1
import deltaTimer;
//from Dialog1 import OpenNotice; // winos
//import ExtFile_IO081;
//from Dialog1 import OpenNotice;
from deltaDialog import OpenNotice;
//import ExtLibrary;
import pdRequest;

import DebugUtilities;
//import process;
import ProcessSerialNumber;

import pdState;
import dynamics;

import DynamicID;

// lazily linked applications
AddClient :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
AddClient client_id [cmdline] s=:{application_path} io
	// initialize dl_client_state
	#! state
		= AddMessage (Verbose "AddClient") EmptyState;
		
	#! name_without_extension
		= ExtractProjectPathName cmdline;

	#! (project_name,dl_client_state,s,io)
		= InitDLClientState DefaultDLClientState client_id name_without_extension False state s io;
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok
		= (True,client_id,AddToDLServerState dl_client_state s,io);
		
	// get messages from dummy client to the real one
	#! (_,dummy_dl_client_state,s)
		= RemoveFromDLServerState client_id s;
	#! (messages,_)
		= GetLinkerMessages dummy_dl_client_state;
	#! dl_client_state
		= SetLinkerMessages messages dl_client_state;

	#! (client_started,client_id,client_executable,dl_client_state,s,io)
		= StartClientApplication dl_client_state s io;
	#! dl_client_state
		= { dl_client_state & id = client_id };
	|  not client_started
		#! msg
			= "file '" +++ client_executable +++ "' cannot be started";
		= (True,client_id,AddToDLServerState (AddMessage (LinkerError msg) dl_client_state) s,io);
		
		// openClientWindow
		#! s
			= AddToDLServerState dl_client_state s;
		#! (s,io)
			= openClientWindow project_name client_id s io;
		= (False,client_id,s,io);
		
Init :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
Init client_id args s io

	#! (client_exists,dl_client_state,s)
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "Init (internal error): client not registered" client_id dl_client_state s io;
		
	#! dl_client_state
		= AddMessage (Verbose "Init") dl_client_state;
		
	// check args-argument of Init-request
	#! dl_client_state
		= case (sel_platform True False) of {
			True
				// winOS
				| not (isEmpty args) 
					#! dl_client_state
						= AddMessage (LinkerError "args argument of Init in Request.icl cannot have arguments") dl_client_state;
					-> dl_client_state;
					-> dl_client_state;
			False
				// macOS
 /*
				| length args <> 1 //isEmpty args
					#! dl_client_state
						= AddMessage (LinkerError "args argument of Init in Request.icl should have exactly one parameter") dl_client_state;
					-> dl_client_state;
					
					#! dl_client_state
						= app_pd_state (\pd_state -> {pd_state & qd_address = FromStringToInt (hd args) 0}) dl_client_state;
					-> dl_client_state;
 */
 				-> abort "Request.icl; Init (line 131) uncomment!!!";

		}

/*
	// test
	#! dl_client_state
		= AddMessage (LinkerWarning "InitialLink2 is *disabled*") dl_client_state;
	#! dl_server_state
		= s;
*/
	
	#! (_,dl_client_state,dl_server_state,io)
		= InitialLink2 /*options_file_name*/ {dl_client_state & initial_link = True} s io;

	// check for errors
	#! (ok,dl_client_state)
		= IsErrorOccured {dl_client_state & initial_link = False};
	= (not ok,client_id,AddToDLServerState dl_client_state dl_server_state,/*KillClient3 client_id ok*/ io);

// platform independent
Quit :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
Quit client_id _ s io
	#! dl_client_state
		= { DefaultDLClientState &
			id					= client_id
		,	app_linker_state	= EmptyState
		};
	= (True,client_id,AddToDLServerState dl_client_state s,io);

// adding code
AddLabel :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
AddLabel client_id [module_name,symbol_name] s io		
	#! (client_exists,dl_client_state,s)
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "AddLabel (internal error): client not registered" client_id dl_client_state s io;

	#! dl_client_state
		= AddMessage (Verbose "AddLabel") dl_client_state;	
	// search, link and load label	
	#! module_name
		= strip_abc_and_o_extension module_name;
	#! (linked,l,dl_client_state,s,io)
		= NewLinkerFunction2 [ModuleUnknown module_name symbol_name] dl_client_state s io;

	// check for errors
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok		
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
		
		#! dl_client_state
			= AddMessage (Verbose ("label " +++ symbol_name +++ " at " +++ (hex_int (hd l)) )) dl_client_state;
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
		
// adding descriptors; used by StdDynamic without version management; to be removed in the near future
AddDescriptors :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
AddDescriptors client_id [string_table] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "AddDescriptors (internal error): client not registered" client_id dl_client_state s io;

	| sel_platform False True
		#! msg 
			= "AddDescriptors: not yet implemented for macOS";
		= (False,client_id,AddToDLServerState dl_client_state s, io);
				
	#! dl_client_state
		= AddMessage (Verbose "AddDescriptors") dl_client_state;	
				
	#! unknown_modules_or_symbols
		= generate_needed_label_names string_table;
		
	// search, link and load descriptors
	#! (linked,l,dl_client_state,s,io)
		= NewLinkerFunction2 unknown_modules_or_symbols dl_client_state s io;

	// check for errors		
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
		
	// verbose		
	#! dl_client_state
		= SetLinkerMessages (produce_verbose_output unknown_modules_or_symbols l []) dl_client_state;
	= (not ok,client_id,AddToDLServerState dl_client_state s,io);

produce_verbose_output [] [] labels
	= labels;

produce_verbose_output [ModuleUnknown module_name label_name:unknown_modules] [label_address:label_addresses] labels
	#! label
		= Verbose ("label " +++ label_name +++ " at " +++ (hex_int label_address));
	= produce_verbose_output unknown_modules label_addresses [label:labels];

produce_verbose_output [SymbolUnknown module_name label_name:unknown_modules] [label_address:label_addresses] labels
	#! label
		= Verbose ("label " +++ label_name +++ " at " +++ (hex_int label_address));
	= produce_verbose_output unknown_modules label_addresses [label:labels];
	
produce_verbose_output _ [] _
	= abort "!produce_verbose_output; no addresses";
	
/*	
produce_verbose_output2 messages {dusl_label_name,dusl_library_instance_i,dusl_linked=True} address
	#! label
		= Verbose ("label " +++ dusl_label_name +++ " at " +++ (hex_int address) +++ " from library instance #" +++ toString dusl_library_instance_i);
	= [label:messages];
*/

produce_verbose_output2 messages {dusl_label_name,dusl_library_instance_i,dusl_linked,dusl_label_kind} address
	#! linked
		= if dusl_linked "linked " "";
	#! label_kind
		= case dusl_label_kind of {
			DSL_RUNTIME_SYSTEM_LABEL
				-> "RTS";
			DSL_TYPE_EQUIVALENT_CLASS_WITH_IMPLEMENTATION
				-> "LINKED TYPE";
			DSL_TYPE_EQUIVALENT_CLASS_IMPLEMENTATION
				-> "UNLINKED TYPE";
			DSL_CLEAN_LABEL_BUT_NOT_A_TYPE
				-> "NON CLEAN TYPE";
			DSL_EMPTY
				-> "EMPTY";
		};
	#! label
		= Verbose (linked +++ "label " +++ dusl_label_name +++ "<" +++ toString dusl_library_instance_i +++ "," +++ label_kind +++ "> at " +++ (hex_int address));
	= [label:messages];
	
	
/*
:: DusLabelKind
	= DSL_EMPTY
	| DSL_RUNTIME_SYSTEM_LABEL
	| DSL_TYPE_EQUIVALENT_CLASS_WITH_IMPLEMENTATION
	| DSL_TYPE_EQUIVALENT_CLASS_IMPLEMENTATION
	| DSL_CLEAN_LABEL_BUT_NOT_A_TYPE
	;
*/


// eager linked applications
AddAndInit :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
AddAndInit client_id [eagerly_linked_client_name,do_add_project] s=:{/*targets,*/application_path} io
	// fill application linker state by reading the complement
	#! state
		= AddMessage (Verbose "AddAndInit") EmptyState;		
	#! (name_without_extension,_)
		= ExtractPathFileAndExtension eagerly_linked_client_name;
	#! (state,io) 
		= case do_add_project == "T" of {
			True
				-> (state,io);
			_
				-> accFiles (ReadState eagerly_linked_client_name state) io;
		};
	
	#! (ok,state)
		= IsErrorOccured state;
	| not ok
		#! dl_client_state
			= { DefaultDLClientState &
				id					= client_id
			,	app_linker_state	= state
			};
			

		#! s
			= AddToDLServerState dl_client_state s;
		#! (s,io)
			= openClientWindow eagerly_linked_client_name client_id s io;
		= (True,client_id,s,io);
		
	// windows specific
	#! state
		= sel_platform (RemoveStaticClientLibrary state) state;
		
	#! (_,dl_client_state,s,io)
		= InitDLClientState DefaultDLClientState client_id name_without_extension False state s io;
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
		
	// openClientWindow
	#! s
		= AddToDLServerState dl_client_state s;
	#! (s,io)
		= openClientWindow eagerly_linked_client_name client_id s io;

	= (not ok,client_id,s,io);
	
Close :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
Close client_id _ s=:{application_path} io
	
	#! (client_exists,dl_client_state=:{client_window},s)
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "Close (internal error): client not registered" client_id dl_client_state s io;
		
	// platform dependent
	#! (dl_client_state,io)
		= CloseClient dl_client_state io;
			
	// update project, if necessary
	#! (updated,dl_client_state)
		= dl_client_state!updated;
	#! (ok,io,dl_client_state)
		= case updated of {
			True				
				// Update is done regardless whether or not the project file has
				// been accessed between the ReadProjectFile and the SaveProject
				// File.
				#! (project,dl_client_state)
					= dl_client_state!project;
				#! (project_name,dl_client_state)
					= dl_client_state!project_name;		
				#! (pdi,project)
					= getDynamicInfo project;
					
				#! ((project,ok_open,error),io)
					= accFiles (ReadProjectFile project_name application_path) io;
				#! project
					= setDynamicInfo pdi project;
				#! (ok_close,io)
					= accFiles (SaveProjectFile project_name project application_path) io;
				-> (ok_open && ok_close,io,dl_client_state);
			False
				-> (True,io,dl_client_state);
		};
	| not ok
		= internal_error "Close: error during project IO" client_id dl_client_state s io;
				
	= (True,client_id,AddToDLServerState dl_client_state s,io);

show_msg l s io
	#! io
		= DisableTimer timer_id io;
	#! (i,s,io)
		= OpenNotice (Notice l (NoticeButton 0 "Ok") []) s io;
	#! io
		= EnableTimer timer_id io;
	= (s, io);


internal_error :: !{#Char} !ProcessSerialNumber !*DLClientState !*DLServerState .a -> *(!Bool,!ProcessSerialNumber,!DLServerState,.a);		
internal_error message client_id dl_client_state=:{app_linker_state=state} s io
	#! dl_client_state
		= { dl_client_state &
			id					= client_id
		,	app_linker_state	= AddMessage (LinkerError message) state
		};
	= (True,client_id,AddToDLServerState dl_client_state s,io);


InitDLClientState dl_client_state client_id name_without_extension project_required state s=:{application_path/*,targets*/} io
	#! dl_client_state
		= { dl_client_state & id = client_id};
	// attempt to read project
	#! project_name 
		= name_without_extension +++ ".prj";
	#! ((project,ok,error),io)
		= accFiles (ReadProjectFile project_name application_path) io;
	| not ok
		= (project_name,{ dl_client_state & app_linker_state = state},s,io);
		
	#! (updated,projectdir,project,state) 
		= case ok of {
			True
				// read project
				#! (project_static_info,project)
					= getStaticInfo project;
				#! projectdir 
					= project_static_info.stat_prj_path;
				-> (False,projectdir,project,state);
			False
				// project could not be read; create a default one
				#! project 
					= PR_InitProject;
				#! (project_static_info,project)
					= getStaticInfo project;
				#! project_dir
					= fst (ExtractPathAndFile name_without_extension);
				#! project_static_info
					= { project_static_info &
					   stat_prj_path = project_dir
					  };
				#! project 
					= setStaticInfo project_static_info project;
					
				// warning
				#! state
					= case project_required of {
						True
							-> AddMessage (LinkerError error) state;
						False 			
							#! msg
								= "project file '" +++ project_name +++ "' cannot be opened";
							-> AddMessage (LinkerWarning msg) state;
					};
				-> (True,project_dir,project,state);
			};
			
/*
	// lookup environment
	#! project_target
		= PR_GetTarget project;
	#! targets
		= filter (\target -> target.target_name == project_target) targets;
	| sel_platform (isEmpty targets) (F "macOs: targets not yet implemented" False)
		#! msg
			= "required environment '" +++ project_target +++ "' not found";
		= (project_name,{dl_client_state & app_linker_state = AddMessage (LinkerError msg) state},s,io);
		
	#! (cg_short_path,targets)
		= sel_platform 
			(snd (GetShortPathName (application_path +++ toString path_separator +++ ((hd targets).target_cgen) +++ "\0")),targets)
			(application_path +++ toString path_separator +++ "Clean Compiler",[emptyTarget]);
	#! target
		= hd targets;
				
	// tijdelijk
	#! target
		= sel_platform 
			target
			{target & target_vers = 918};
*/

	// create client state
	#! dl_client_state
		= { dl_client_state &
		// client identification
			id					= client_id
//		,	target				= target //hd targets
//		,	cgpath				= cg_short_path
					
		// project settings
		,	project 			= project
		,	updated				= updated
		,	project_name		= project_name
		
		// application linker state
		,	app_linker_state	= state
		};
				
	= (project_name,dl_client_state,s,io);
	
// add a project
AddProject :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
AddProject client_id [args_encoded_as_string] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "AddProject (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "AddProject") dl_client_state;

	#! paths
		= ExtractArguments '\n' 0 args_encoded_as_string [];
		
		
	#! (dl_client_state)
		= AddMessage (Verbose ("add project " +++ (hd paths))) dl_client_state;

	#! name_without_extension
		= fst (ExtractPathFileAndExtension (hd paths));
		

	#! (state,dl_client_state)
//		= w (\state -> (state,EmptyState)) dl_client_state;
		= /*F "AddProject: reset" */ (EmptyState,{ dl_client_state & initial_link = True})
			
	#! (project_name,dl_client_state,s,io)
		= InitDLClientState dl_client_state client_id name_without_extension False state s io;
		
	#! (_,dl_client_state,s,io)
		= InitialLink2 /*options_file_name*/ {dl_client_state & initial_link = True} s io;
	= (False,client_id,AddToDLServerState dl_client_state s,io);
where {
	w f dl_client_state=:{app_linker_state}
		#! (x,app_linker_state)
			= f app_linker_state;
		= (x, {dl_client_state & app_linker_state = app_linker_state});
};

// adding addresses
GetAddresses :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
GetAddresses client_id [label_names_encoded_in_msg] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| F "GetAddresses" not client_exists
		= internal_error "GetAddresses (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "GetAddresses") dl_client_state;

	#! symbols
		= ExtractArguments '\n' 0 label_names_encoded_in_msg [];

	#! unknown_modules_or_symbols
		= [ SymbolUnknown "" s \\ s <- symbols]


	// search, link and load descriptors
	#! (linked,l,dl_client_state,s,io)
		= NewLinkerFunction2 unknown_modules_or_symbols dl_client_state s io;

	// check for errors		
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
		
	// verbose		
	#! dl_client_state
		= SetLinkerMessages (produce_verbose_output unknown_modules_or_symbols l []) dl_client_state;
	= (not ok,client_id,AddToDLServerState dl_client_state s,io);

// lookup addresses of some already linked in labels
GetLabelAddresses :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
GetLabelAddresses client_id [label_names_encoded_in_msg] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| F "GetLabelAddresses" not client_exists
		= internal_error "GetLabelAddresses (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "GetLabelAddresses") dl_client_state;

	#! symbols
		= ExtractArguments '\n' 0 label_names_encoded_in_msg [];

//LoadLibraryInstance_new library_instance_i labels_to_be_linked dl_client_state /*s*/ io


	#! (Just main_library_instance_i,dl_client_state)
		= dl_client_state!cs_main_library_instance_i;


	#! (labels_to_be_linked,_)
		= mapSt (convert_symbol_name_into_dus_label main_library_instance_i) symbols 0;		

	#! (symbol_addresses,dl_client_state,io)
		= LoadLibraryInstance_new main_library_instance_i (Just labels_to_be_linked) dl_client_state io;

	// check for errors		
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
	
	// verbose	
	#! messages
		= foldl2 produce_verbose_output2 [] labels_to_be_linked symbol_addresses;
	#! dl_client_state
		= SetLinkerMessages messages dl_client_state ;
	// end
	
	#! io
		= SendAddressToClient client_id symbol_addresses io;
		
	= (not ok,client_id,AddToDLServerState dl_client_state s,io);
where {
	convert_symbol_name_into_dus_label library_instance_i label_name ith_address
		#! dus_label
			= { default_elem &
				dusl_label_name				= label_name
			,	dusl_library_instance_i		= library_instance_i
			,	dusl_linked					= False
			,	dusl_label_kind				= DSL_EMPTY
			,	dusl_ith_address			= ith_address
			,	dusl_address				= -1
			};
		= (dus_label,inc ith_address);
}

ComputeDescAddressTable :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
ComputeDescAddressTable client_id [args] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| F "ComputeDescAddressTable" not client_exists
		= internal_error "ComputeDescAddressTable (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "ComputeDescAddressTable") dl_client_state;

	#! args
		= ExtractArguments '\n' 0 args [];
	| length args <> 1   //2
		= internal_error "ComputeDescAddressTable (internal error): didn't get expected arguments" client_id dl_client_state s io;

/*
	// get header_fp and file_name of the dynamic
	#! header_fp
		= FromStringToInt (hd args) 0;
*/	
	#! file_name
		= hd args //(tl args);

		
	// get stringtable and descriptor address table
	#! ((ok,version,stringtable,desc_address_table),io)
		= accFiles (read_stringtable_and_desc_address_table file_name /*header_fp*/) io;
		
	#! unknown_modules_or_symbols
		= generate_needed_label_names2 stringtable desc_address_table;
	
	#! (ok,latest_version,dl_client_state,s)
		= eager_read_version version dl_client_state s;

	#! (dlink_dir,s)
		= GetDynamicLinkerDirectory s;
	#! module_name
		= dlink_dir +++ "\\" +++ copy_string_to_graph +++ "_" +++ (toFileNameSubString latest_version) +++ ".obj";
	#! symbol_name
		= "e____SystemDynamic__d" +++ copy__string__to__graph +++ "__" +++ toFileNameSubString latest_version;

	#! unknown_modules_or_symbols
		= [ModuleUnknown module_name symbol_name:unknown_modules_or_symbols];


	// copy of AddDescriptors ...				
	// search, link and load descriptors
	#! (linked,l,dl_client_state,s,io)
		= NewLinkerFunction2 unknown_modules_or_symbols dl_client_state s io;

	// check for errors		
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
		
	// verbose		
	#! dl_client_state
		= SetLinkerMessages (produce_verbose_output unknown_modules_or_symbols l []) dl_client_state;
	= (not ok,client_id,AddToDLServerState dl_client_state s,io);
	// ... copy of AddDescriptors
	
ComputeDescAddressTable2_n_args					:== 4;
ComputeDescAddressTable2_n_copy_request_args	:== 6;

import memory_mapped_files;

RegisterLazyDynamic :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
RegisterLazyDynamic client_id [args] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| /*F "ComputeDescAddressTable2"*/ not client_exists
		= internal_error "RegisterLazyDynamic (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "RegisterLazyDynamic") dl_client_state;

	#! args
		= ExtractArguments '\n' 0 args [];
	#! l_args
		= length args;
	#! rt_lazy_dynamic_index
		= FromStringToInt (hd args) 0;			// run-time ptr

	// Using the run-time lazy dynamic index (rt_lazy_dynamic_index), the id of the main dynamic i.e. the 
	// top-level dynamic is determined. 
	#! (result,dl_client_state)
		= get_dynamic_id rt_lazy_dynamic_index dl_client_state
	| isNothing result
		= abort "RegisterLazyDynamic; get_dynamic_id; lazy_dynamic_index cannot be found";
		
	// dynamic found
	// 1. map file
	// 2. initialize dynamic (using code in ComputeDescAddressTable2)
	#! (disk_lazy_dynamic_index,id)
		= fromJust result;
	#! main_dynamic_id
		= id; // run-time pointer

	// extract file name from dynamic containing the lazy dynamic	
	# (file_name,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_lazy_dynamics_a.[disk_lazy_dynamic_index];

	// assign the lazy dynamic a run-time id
	#! (id,dl_client_state)
		= new_dynamic_id dl_client_state;
	#! lazy_dynamic_id
		= id;
		
	#! (has_lazy_dynamic_already_been_initialized,dl_client_state)
		= dl_client_state!cs_lazy_dynamic_index_to_dynamic_id.[rt_lazy_dynamic_index];
	#! initialized_lazy_dynamic
		= isJust has_lazy_dynamic_already_been_initialized
		// the dynamic associated from which the build_lazy_block wants to build a block has already
		// been initialized.
//		= abort "RegisterLazyDynamic; lazy dynamic from which a block is required, has already been registered!!";
		
	#! dl_client_state
		= case initialized_lazy_dynamic of {
			True	-> dl_client_state;
			_		-> { dl_client_state & cs_lazy_dynamic_index_to_dynamic_id.[rt_lazy_dynamic_index] = Just id };
		};
		
	// map file into memory of client ...
	# client_process_id
		= GetOSProcessSerialNumber client_id;
	# (dynamic_rts_process_handle,st)
		= OpenProcess (STANDARD_RIGHTS_REQUIRED bitor PROCESS_ALL_ACCESS) FALSE client_process_id initialState;

	# (ok,file,exported_handle)
		= CreateSharedBufferFromFile2 dynamic_rts_process_handle file_name;
	| not ok
		= abort "could not create memory mapped file";

	// body ...		

	# (file,id,dl_client_state,io)
		= case initialized_lazy_dynamic of {
			False
				# (ok,dynamic_header,file)
					= read_dynamic_header file;
				| not ok
					-> abort "get_tables_from_dynamic: error reading dynamic header";
			
				# (file,id,dl_client_state,io)
					= read_from_dynamic id file_name file dl_client_state io dynamic_header;
				-> (file,id,dl_client_state,io);
			True
				-> (file,fromJust has_lazy_dynamic_already_been_initialized,dl_client_state,io);
		};
			
	| not (CloseExistingSharedBuffer file) || not (CloseST st)
		= abort "stop";
	// ... map file into memory of client
	
	// initialize dynamic
	#! (dl_client_state,io)
		= case initialized_lazy_dynamic of {
			False
				#! (_,dl_client_state,io)
					= init_lazy_dynamic id dl_client_state io;

				// enter initialized type equations
				#! dl_client_state
					= enter_lazy_type_equations main_dynamic_id (lazy_dynamic_id,disk_lazy_dynamic_index) dl_client_state;
				-> (dl_client_state,io);
			True
				-> (dl_client_state,io);
		};
		
	# (di_string_table,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_string_table;

	// msg ...
	#! (library_instance_runtime_ids,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_disk_id_to_library_instance_i;
	#! (di_disk_to_rt_dynamic_indices,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_disk_to_rt_dynamic_indices;
	
	// due to 1.3 bug, a six tuple cannot be exported. Therefore I pack the file_name
	// with the exported handle.
	#! msg
		= ((exported_handle,
		file_name),
		library_instance_runtime_ids,
		// lazy dynamics...
		 di_disk_to_rt_dynamic_indices,
		// ... lazy dynamics
		id);
	// ... msg

	#! io
		= SendAddressToClient client_id (encode msg) io;
	#! ok = True
	= (not ok,client_id,AddToDLServerState dl_client_state s,io);
where {
	enter_lazy_type_equations rt_main_dynamic_id (rt_lazy_dynamic_id,disk_lazy_dynamic_index) dl_client_state
		# (di_disk_type_equivalent_classes,dl_client_state)
			= dl_client_state!cs_dynamic_info.[rt_main_dynamic_id].di_disk_type_equivalent_classes;
			
		# (new_di_disk_type_equivalent_classes,dl_client_state)
			= mapASt examine_disk_type_equivalent_class di_disk_type_equivalent_classes ([],dl_client_state); 
			
		# dl_client_state
			= { dl_client_state & 
				cs_dynamic_info.[rt_main_dynamic_id].di_disk_type_equivalent_classes = { x \\ x <- new_di_disk_type_equivalent_classes } };
		= dl_client_state;
	where {
		examine_disk_type_equivalent_class old_dtec=:{dtec_type_implementation_table_index,dtec_type_equations,dtec_lazy_type_equations} (l,dl_client_state)
			| s_dtec_type_equations <> 0 && s_dtec_lazy_type_equations == 0 <<- ("allo",size dtec_lazy_type_equations,size dtec_type_equations)
				// skip eager type equation because they have already been entered in init_dynamic.
				= (l,dl_client_state);
			
			// The set of lazy type equation (with at least size one) is split into:
			// * a set of type equations of an initialized lazy dynamic, these equations have to be added to 
			//   type implementation table. 
			// * a set of type equations of an *un*initialized lazy dynamic
			// A type equation is initialized if the lazy dynamic to which it belongs, has been initialized.
			#! (initialized_lazy_type_equations,uninitialized_lazy_type_equations,dl_client_state)
				= mapASt split_lazy_type_equations dtec_lazy_type_equations ([],[],dl_client_state);
				
			#! (n_initialized_lazy_type_equations,n_uninitialized_lazy_type_equations)
				= (length initialized_lazy_type_equations,length uninitialized_lazy_type_equations);
				
			| isNothing dtec_type_implementation_table_index
				// none of the type equations of current type equivalent class have yet been entered into the
				// type implementation table.
				| s_dtec_type_equations + n_initialized_lazy_type_equations < 2
					// a type equivalent class consists of at least two type equations but there are less than
					// two type equations to be entered. Therefore the type equivalent class is *not* created
					// until uninitialized lazy type equation becomes initialized. 
					= abort ("still nothing to be entered" +++ (toString (s_dtec_type_equations + n_initialized_lazy_type_equations)));
				
					// Encode the eager type equations
					# (decoded_eager_type_equations,dl_client_state)
						= mapSt convert_disk_type_references_to_runtime_type_references [ type_equation \\ type_equation <-: dtec_type_equations ] dl_client_state;
					# type_equations 
						= initialized_lazy_type_equations ++ decoded_eager_type_equations;
						
//					#! dl_client_state
//						= AddMessage (Verbose "ADDING LAZY TYPE EQUATIONS") dl_client_state;

					// add initialized eager/lazy type equations; type equation always have an icl-definition
					# (type_implementation_reference,dl_client_state)
						= foldSt (enter_initial_type_equations (hd type_equations)) (tl type_equations) (0,dl_client_state);
						
					# l
						= case (n_uninitialized_lazy_type_equations == 0) of {
							True
								// discard type equivalent class because all type equations have been entered
								// into the type implementation table.
								-> l;
							False
								# dtec
									= { default_elem &
										dtec_lazy_type_equations				= { x \\ x <- uninitialized_lazy_type_equations }
									,	dtec_type_implementation_table_index	= Just type_implementation_reference
									};
								-> [dtec:l];
						};
					= (l,dl_client_state);
					
			// The current type equivalent class
			// - dtec_type_equations is {}
			// - size dtec_lazy_type_equations > 0
			// - dtec_type_implementation_table_index is Just type_implementation_reference
			| n_initialized_lazy_type_equations == 0
				// there are no lazy type equations initialized by adding the current lazy dynamic.
				// consistency check
				| n_uninitialized_lazy_type_equations == 0
					= abort "examine_disk_type_equivalent_class; internal error; empty type equivalent classes not allowed";
				= (l,dl_client_state);
				
			// add initialized lazy type equations
			# dl_client_state
				= add_lazy_type_equations (fromJust dtec_type_implementation_table_index) initialized_lazy_type_equations dl_client_state;
				
			# l
				= case (n_uninitialized_lazy_type_equations == 0) of {
					True
						// discard type equivalent class because all type equations have been entered
						// into the type implementation table.
						-> l;
					False
						# dtec
							= { old_dtec &
								dtec_lazy_type_equations	= { x \\ x <- uninitialized_lazy_type_equations }
							};
						-> [dtec:l];
				};
			= (l,dl_client_state);
		where {
			s_dtec_type_equations
				= size dtec_type_equations;
				
			s_dtec_lazy_type_equations
				= size dtec_lazy_type_equations;
				
			// enters eager/lazy type equations. It is assumed that there are at least two type equations.	
			enter_initial_type_equations type1 type2 (r,dl_client_state)
				# (/*type_implementation_table_reference,created_new_type_equivalence_class*/ maybe_ref,dl_client_state)
					= enter_type_equation type1 type2 dl_client_state;
				| isNothing maybe_ref
					= (r,dl_client_state);
	
					= (fst (fromJust maybe_ref),dl_client_state);
				
				
			// The set of lazy type equation is split into:
			// * a set of type equations of an initilized lazy dynamic 
			// * a set of type equations of an *un*initialized lazy dynamic
			split_lazy_type_equations (ldtr=:(LazyDiskTypeRef {ldtr_lazy_dynamic_index,ldtr_disk_type_ref={dtr_library_instance_i,dtr_tr_module_n,dtr_tr_type_def_n} })) (initialized_lazy_type_equations,uninitialized_lazy_type_equations,dl_client_state)
				// convert ldtr_lazy_dynamic_index into corresponding run-time lazy dynamic index if possible
				# (rt_lazy_dynamic_index,dl_client_state)
					= dl_client_state!cs_dynamic_info.[rt_main_dynamic_id].di_disk_to_rt_dynamic_indices.[ldtr_lazy_dynamic_index];
				# (maybe_lazy_dynamic_id,dl_client_state)
					= dl_client_state!cs_lazy_dynamic_index_to_dynamic_id.[rt_lazy_dynamic_index];
				| isNothing maybe_lazy_dynamic_id
					// uninitialized lazy dynamic. 
					= (initialized_lazy_type_equations,[ldtr:uninitialized_lazy_type_equations],dl_client_state); 

					// initialized lazy dynamic, build type equation
					# lazy_dynamic_id
						= fromJust maybe_lazy_dynamic_id;
					# (rt_library_instance_i,dl_client_state)
						= dl_client_state!cs_dynamic_info.[lazy_dynamic_id].di_disk_id_to_library_instance_i.[dtr_library_instance_i];

					# tio_type_reference
						= { default_elem &
						    tio_tr_module_n		= dtr_tr_module_n
						,   tio_tr_type_def_n 	= dtr_tr_type_def_n
						};
					# tttr
						= LIT_TypeReference rt_library_instance_i tio_type_reference;
					= ([tttr:initialized_lazy_type_equations],uninitialized_lazy_type_equations,dl_client_state); 

				// converts a type reference from its encoded representation to its run-time representation.		
				convert_disk_type_references_to_runtime_type_references (DiskTypeRef {dtr_library_instance_i,dtr_tr_module_n,dtr_tr_type_def_n}) dl_client_state
					# (rt_library_instance_i,dl_client_state)
						= dl_client_state!cs_dynamic_info.[rt_main_dynamic_id].di_disk_id_to_library_instance_i.[dtr_library_instance_i];
					# tio_type_reference
						= { default_elem &
						    tio_tr_module_n		= dtr_tr_module_n
						,   tio_tr_type_def_n 	= dtr_tr_type_def_n
						};
					# tttr
						= LIT_TypeReference rt_library_instance_i tio_type_reference;
					= (tttr,dl_client_state);
			
			collect_initialized_lazy_dynamics_for_main_dynamic disk_lazy_dynamic_index rt_lazy_dynamic_index (initialized_lazy_dynamics,dl_client_state)
				#! (maybe_initialized_lazy_dynamic,dl_client_state)
					= dl_client_state!cs_lazy_dynamic_index_to_dynamic_id.[rt_lazy_dynamic_index];
				| isNothing maybe_initialized_lazy_dynamic
					= (initialized_lazy_dynamics,dl_client_state);
					
					# initialized_lazy_dynamics
						= { initialized_lazy_dynamics & [disk_lazy_dynamic_index] = maybe_initialized_lazy_dynamic };
					= (initialized_lazy_dynamics,dl_client_state);
		
		
		}; // examine_disk_type_equivalent_class
	}; // enter_lazy_type_equations

	get_dynamic_id searched_rt_lazy_dynamic_index dl_client_state
		#! (n_dynamics,dl_client_state)
			= dl_client_state!dynamic_ids.did_counter;
		#! (result,dl_client_state)
			= findAst is_searched_dynamic_index dl_client_state n_dynamics; 
		= (result,dl_client_state);
	where {
		is_searched_dynamic_index dynamic_index dl_client_state
			// determine whether the dynamic id is valid
			# (is_valid_dynamic_index,dl_client_state)
				= is_valid_id2 dynamic_index dl_client_state;
			| not is_valid_dynamic_index
				= (Nothing,dl_client_state);

			// valid, extract array holding all run-time lazy dynamic indices
			# (di_disk_to_rt_dynamic_indices,dl_client_state)
				= dl_client_state!cs_dynamic_info.[dynamic_index].di_disk_to_rt_dynamic_indices;
//			| True <<- ("^^^",searched_rt_lazy_dynamic_index,di_disk_to_rt_dynamic_indices)
			# result
				= findAi is_lazy_disk_dynamic di_disk_to_rt_dynamic_indices;
			= (result,dl_client_state);
		where {
			is_lazy_disk_dynamic disk_lazy_dynamic_index rt_lazy_dynamic_index 
				| searched_rt_lazy_dynamic_index == rt_lazy_dynamic_index
					= Just (disk_lazy_dynamic_index,dynamic_index);
					= Nothing;
		}; // is_searched_dynamic
	} // get_dynamic_id			
};
	
import StdDynamicSharedBuffer;

init_lazy_dynamic id dl_client_state io
	= init_dynamic2 "LAZY DYNAMIC" True id dl_client_state io;

// physically reads in file and initializes the administration for the dynamic by init_dynamic2
init_dynamic file_name False id block_i args dl_client_state io
	= (id,dl_client_state,io);
init_dynamic file_name first_time id block_i args dl_client_state io
	// create a new id
	#! (id,dl_client_state)
		= new_dynamic_id dl_client_state;

	#! msg
		= "** Encoded a dynamic (e.g. from disk): " +++ toString id;
	#! (dl_client_state)
		= AddMessage (Verbose msg) dl_client_state;
	
	# (id,dl_client_state,io)
		= get_tables_from_dynamic args file_name id dl_client_state io;		
	#! msg
		= "dynamic: '" +++ file_name +++ "' id: " +++ toString id +++" block: " +++ toString block_i;
	#! (dl_client_state)
		= AddMessage (Verbose msg) dl_client_state;
	= init_dynamic2 file_name first_time id dl_client_state io;
where {
	get_tables_from_dynamic args file_name id dl_client_state io
		#! dynamic_access
			= case (size args) of {
				ComputeDescAddressTable2_n_args
					-> "FILE";		// file containing dynamic is read by dynamic rts
				ComputeDescAddressTable2_n_copy_request_args 
					-> "VIEW";		// view passed by the rts is read by dynamic rts
			};
		#! dl_client_state
 			= AddMessage (Verbose ("dynamic access: " +++ dynamic_access)) dl_client_state;
		| size args == ComputeDescAddressTable2_n_args
			// open dynamic
			#! (ok,dynamic_header,file,io)
				= open_dynamic_as_binary file_name io;
			| not ok
				#! (_,io)
					= close_dynamic_as_binary file io;
				#! msg
					= "could not open dynamic '" +++ file_name +++ "'";
				#! dl_client_state
					= AddMessage (LinkerError msg) dl_client_state;
				= (0,dl_client_state,io);

			# (file,id,dl_client_state,io)
				= read_from_dynamic id file_name file dl_client_state io dynamic_header;
			# (_,io)
				= close_dynamic_as_binary file io;

			= (id,dl_client_state,io);
		| size args == ComputeDescAddressTable2_n_copy_request_args
			# file_mapping_handle
				= toInt args.[4];
			# s_buffer
				= toInt args.[5];

			# (ok,file)
				= OpenExistingSharedBuffer file_mapping_handle s_buffer
			| not ok
				= abort "get_tables_from_dynamic: OpenExistingSharedBuffer failed";
				
			# (ok,dynamic_header,file)
				= read_dynamic_header file;
			| not ok
				= abort "get_tables_from_dynamic: error reading dynamic header";
				

			# (file,id,dl_client_state,io)
				= read_from_dynamic id file_name file dl_client_state io dynamic_header;
					
			| CloseExistingSharedBuffer file
				= (id,dl_client_state,io);
				= abort "unreachable";

}	

init_dynamic2 file_name first_time id dl_client_state io
	#! ({di_disk_type_equivalent_classes,di_n_blocks},dl_client_state)
		= dl_client_state!cs_dynamic_info.[id];
	| di_n_blocks <= 0
		= abort "init_dynamic2; internal error; dynamic has no blocks";
		
	#! (stringtable,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_string_table;
	#! (descriptor_usage_table,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_descriptor_usage_table;

	// get info about the library instances used by the dynamic
	# (di_library_instance_to_library_index,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_library_instance_to_library_index;
	# (di_library_index_to_library_name,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_library_index_to_library_name;
							
	# library_instance_runtime_ids	// indexed by RunTimeID(diskID) to obtain library instance id
		= force_unboxed_int_array (createArray (size di_library_instance_to_library_index) (-1));
		
	# (library_instance_runtime_ids,_,dl_client_state,io)
		= mapAiSt convert_string_id_to_runtime_id_for_a_library_instance di_library_instance_to_library_index 
			(library_instance_runtime_ids,di_library_index_to_library_name,dl_client_state,io);
	
	
	// Each dynamic has type equations which ensure that equivalent types have a single, unique representation
	// within a dynamic or even among several dynamics. It should be noted that by several does not imply all
	// dynamics: it depends upon the external types of dynamics which directly or indirectly could use the 
	// dynamic being initialized here.
	// All lazy type equations are ignored here because the associated dynamics have not yet been initialized
	// let alone built which implies that the types implementations needed by these lazy dynamics can never
	// have been linked in already, so no type equations are needed to enforce this. Upon the first block built
	// of a lazy dynamic, the situation changes.
	// Hence only (eager) type equations will be stored in the type implementation table which is done below:
	// ...
	# dl_client_state
		= mapASt (enter_eager_type_equation_in_type_implementation_table) di_disk_type_equivalent_classes dl_client_state;
	// ...
	
	// ComputeDescAddress still contains diskIDs instead of real RunTimeIDs, so the conversion table
	// must be preserved.
	# dl_client_state
		= { dl_client_state & 
			cs_dynamic_info.[id].di_disk_id_to_library_instance_i = library_instance_runtime_ids
		,	cs_dynamic_info.[id].di_has_block_been_used = createArray di_n_blocks False
		};

	// printing					
	#! dl_client_state
		= AddMessage (Verbose "References to type-libraries i.e. type tables") dl_client_state;
	#! (type_tables,dl_client_state)
		= get_type_tables dl_client_state;
	#! (type_tables,dl_client_state)
		= loopAfill print_library_name type_tables dl_client_state;
		
	// lazy dynamics ...
	#! (di_lazy_dynamics_a,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_lazy_dynamics_a;
	#! (cs_n_lazy_dynamics,dl_client_state)
		= dl_client_state!cs_n_lazy_dynamics;
	
	#! n_lazy_disk_dynamics
		= size di_lazy_dynamics_a;
	#! di_disk_to_rt_dynamic_indices
		= createArray n_lazy_disk_dynamics 0;
	
	// allocate lazy dynamic ids for each lazy disk dynamic id
	#! (di_disk_to_rt_dynamic_indices,cs_n_lazy_dynamics)
		= loopAst (
		\index (di_disk_to_rt_dynamic_indices,cs_n_lazy_dynamics) ->
			let {
				cs_next_lazy_dynamic 
					= inc cs_n_lazy_dynamics
			}
			in 
				({di_disk_to_rt_dynamic_indices & [index] = cs_n_lazy_dynamics},cs_next_lazy_dynamic)
		) 
		(di_disk_to_rt_dynamic_indices,cs_n_lazy_dynamics) n_lazy_disk_dynamics;
		
		
	// extend array to include new lazy dynamics
	#! (cs_lazy_dynamic_index_to_dynamic_id,dl_client_state)
		= get_lazy_dynamic_index_to_dynamic_id dl_client_state;
	#! (_,cs_lazy_dynamic_index_to_dynamic_id)
		= extend_array_nu n_lazy_disk_dynamics cs_lazy_dynamic_index_to_dynamic_id;
	#! dl_client_state
		= { dl_client_state & cs_lazy_dynamic_index_to_dynamic_id = cs_lazy_dynamic_index_to_dynamic_id };
		
		// DLCLientState DLState
		
		
//	| size di_disk_to_rt_dynamic_indices > 1 <<- ("***",di_disk_to_rt_dynamic_indices)
//		= abort "aaaa"; //True <<- ("***",di_disk_to_rt_dynamic_indices)
				
	#! dl_client_state
		= { dl_client_state &
			cs_n_lazy_dynamics	= cs_n_lazy_dynamics
		};
	
	# dl_client_state
		= { dl_client_state & cs_dynamic_info.[id].di_disk_to_rt_dynamic_indices = di_disk_to_rt_dynamic_indices };
	// ... lazy dynamics
										
	// updating
	#! dl_client_state
		= { dl_client_state & cs_type_tables = type_tables };

	= (id,dl_client_state,io);
where {
	enter_eager_type_equation_in_type_implementation_table {dtec_type_equations,dtec_lazy_type_equations} dl_client_state
	// check ...
		// A type equivalent class consisting of a single (or zero) elements should not have
		// been stored, because there is no connection to type in an another library instance.
		| s_dtec_type_equations + s_dtec_lazy_type_equations < 2
			= abort "enter_eager_type_equation_in_type_implementation_table";
	// ... check
			
		| s_dtec_type_equations <= 1
			= dl_client_state;
			
		// Current dynamic has at least two type equations which must be enforced upon the images
		// of the used library instances of the dynamic being initialized. The following must be
		// done:
		// 1. insert the type equations in type implementation table 
		// 2. remove all disk_type_equivalent_class having s_dtec_lazy_type_equations == 0
		= abort "enter_eager_type_equation_in_type_implementation_table: stored type equations are not fully implemented";
	where {
		s_dtec_type_equations
			= size dtec_type_equations;
		s_dtec_lazy_type_equations
			= size dtec_lazy_type_equations;
	};
/*
mapASt f a s :== map_a_st 0 (size a) f a s
where {
	map_a_st i limit f a s
		| i == limit
			= s;
			= map_a_st (inc i) limit f a (f a.[i] s);
}; 

*/	

	
	force_unboxed_int_array :: !*{#Int} -> !*{#Int};
	force_unboxed_int_array i = i;
	
	convert_string_id_to_runtime_id_for_a_library_instance library_instance_string_id {litlii_index_in_di_library_index_to_library_name=library_name_i}
			s=:(library_instance_runtime_ids,di_library_index_to_library_name,dl_client_state,io)
		// skip reserved elements
		| library_instance_string_id < RTID_DISKID_RENUMBER_START 
			= s //<<- (library_instance_string_id, "not accepted");

		// convert string index for a library instance into a run-time index for that library instance
		# library_name
			= di_library_index_to_library_name.[library_name_i];
		# (library_instance_i,_,dl_client_state,io)
			= RegisterLibrary (Just id) False library_name dl_client_state io;
			
		# library_instance_runtime_ids
			= { library_instance_runtime_ids & [library_instance_string_id] = library_instance_i };
		= (library_instance_runtime_ids,di_library_index_to_library_name,dl_client_state,io);
		
	print_library_name i a dl_client_state
		// printing
		#! (tt_name,a)
			= a![i].tt_name;
		#! (tt_loaded,a)
			= a![i].tt_loaded;

		#! msg
			= toString i +++ (if tt_loaded " (Loaded)" " (Not loaded)") +++ ": " +++ tt_name;
		#! dl_client_state
			= AddMessage (Verbose msg) dl_client_state;
		= (a,dl_client_state);
};

read_from_dynamic :: !Int !String !*f !*DLClientState !.a !.DynamicHeader -> *(!*f,!Int,!*DLClientState,!.a) | BinaryDynamicIO f;
read_from_dynamic id file_name file dl_client_state io dynamic_header
	// read descriptor usage set table
	#! (ok,descriptor_usage_table,file)
		= read_descriptor_usage_table_from_dynamic dynamic_header file;
	| not ok
		#! msg
			= "could not read descriptor usage table '" +++ file_name +++ "'";
		#! dl_client_state
			= AddMessage (LinkerError msg) dl_client_state;
		= (file,0,dl_client_state,io);
	
	// read string table
	#! (ok,stringtable,file)
		= read_string_table_from_dynamic dynamic_header file;
	#! dl_client_state
		= case ok of {
			True
				-> dl_client_state;
			False
				#! msg
					= "could not read string table from '" +++ file_name +++ "'";
				-> AddMessage (LinkerError msg) dl_client_state;
		};
		
	// read block table
	#! (ok,block_table,file)
		= read_block_table_from_dynamic dynamic_header file;
	#! dl_client_state
		= case ok of {
			True
				-> dl_client_state;
			False
				#! msg
					= "could not read block table from '" +++ file_name +++ "'";
				-> AddMessage (LinkerError msg) dl_client_state;
		};
		
	// read dynamic rts info
	#! (lib_link,dl_client_state)
		= dl_client_state!lib_link;
	#! (ok2,dynamic_info,file)
		= case lib_link of {
				True	-> read_rts_info_from_dynamic dynamic_header file;
				_		-> (True,default_dynamic_info,file);
		};
		
	#! dl_client_state
		= case ok2 of {
			True
				-> dl_client_state;
			False
				#! msg
					= "could not read dynamic rts info from '" +++ file_name +++ "'";
				-> AddMessage (LinkerError msg) dl_client_state;
		};
	# dynamic_info
		= { dynamic_info &
			di_string_table				= stringtable
		,	di_descriptor_usage_table	= descriptor_usage_table
		,	di_version					= toVersion dynamic_header.version_number
		,	di_file_name				= file_name
		,	di_n_blocks					= size block_table
		};
	# dl_client_state
		= UpdateDynamicInfo id dynamic_info dl_client_state
	= (file,id,dl_client_state,io);


ComputeDescAddressTable2 :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
ComputeDescAddressTable2 client_id [args] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| /*F "ComputeDescAddressTable2"*/ not client_exists
		= internal_error "ComputeDescAddressTable2 (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "ComputeDescAddressTable2") dl_client_state;

	#! args
		= ExtractArguments '\n' 0 args [];
	#! l_args
		= length args
	#! is_non_copy_request
		= (l_args == ComputeDescAddressTable2_n_args);
	#! is_copy_request
		= (l_args == ComputeDescAddressTable2_n_copy_request_args);
	| not (is_non_copy_request || is_copy_request)
		= internal_error ("ComputeDescAddressTable2 (internal error): didn't get expected arguments " +++ toString l_args) client_id dl_client_state s io;

	// extract arguments
	#! args
		= h { arg \\ arg <- args };
	#! file_name
		= args.[0];
	#! first_time
		= args.[1] == "True";
	#! id
		= toInt args.[2];
	#! block_i
		= toInt args.[3];
		
		
	#! (id,dl_client_state,io)
		= init_dynamic file_name first_time id block_i args dl_client_state io;
		
	// mark block as used ...
	#! (di_has_block_been_used,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_has_block_been_used;
	#! di_has_block_been_used
		= { x \\ x <-: di_has_block_been_used };		// make unique
	#! dl_client_state
		= { dl_client_state & 
			cs_dynamic_info.[id].di_has_block_been_used = { di_has_block_been_used & [block_i] = True }
		};
	// ... mark block as used
		
	#! (lib_link,dl_client_state)
		= dl_client_state!lib_link;			
	# ({di_version,di_string_table,di_descriptor_usage_table,di_library_instance_to_library_index},dl_client_state)
		= dl_client_state!cs_dynamic_info.[id];

	#! n_disk_libraries
		= size di_library_instance_to_library_index;
	#! used_disk_libraries
		= NewBitSet n_disk_libraries;
	#! (n_addresses,used_disk_libraries)
		= mapAiSt (compute_used_libraries_in_current_block block_i) di_descriptor_usage_table (0,used_disk_libraries);
	#! (used_disk_libraries,(dus_labels,dl_client_state,s,io))
		= enum_setSt (link_library_instance di_string_table di_descriptor_usage_table block_i id n_addresses) used_disk_libraries ([],dl_client_state,s,io);
	
	// -----------------------------------------------
// old ...		
	#! (unknown_modules_or_symbols,_)
		= ([],[]);
//			(generate_needed_label_names4 block_i stringtable di_descriptor_usage_table dl_client_state id);
// OLD

	#! (ok,latest_version,dl_client_state,s)
		= eager_read_version di_version dl_client_state s;

	#! (dlink_dir,s)
		= GetDynamicLinkerDirectory s;
	#! module_name
		= dlink_dir +++ "\\" +++ copy_string_to_graph +++ "_" +++ (toFileNameSubString latest_version) +++ ".obj";
	#! symbol_name
		= "e____SystemDynamic__d" +++ copy__string__to__graph +++ "__" +++ toFileNameSubString latest_version;
		
// OLD ...
	#! unknown_modules_or_symbols
		= [];
// ... OLD 

	// copy of AddDescriptors ...				
	// search, link and load descriptors
	#! (/*unknown_modules_or_symbols,*/dus_labels,(linked,symbol_addresses,dl_client_state,s,io))
		= case (lib_link) of { //lib_link of {
			True
			/* OLD
				#! (dl_client_state,s,io)
					= foldSt load_library dus_labels (dl_client_state,s,io);
					
				#! dus_labels
					= { dus_label \\ dus_label <- dus_labels };
				#! addresses
					= createArray (size dus_labels) 0;
				#! (dus_labels,(addresses,dl_client_state))
					= mapAeiauSt compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class dus_labels (addresses,dl_client_state);
					
					
				// dummy impl
//				#! (used_library_instances,(addresses,dus_labels,dl_client_state))
//					= enum_setSt compute_label_addresses_for_each_library_separately used_library_instances (addresses,dus_labels,dl_client_state);
				*/
				
				// new ...
				#! addresses
					= createArray n_addresses 0;
				#! dus_labels_a
					= createArray n_addresses default_elem;
				
				#! (addresses,dus_labels)
					= foldSt fill_addresses_and_dus_labels dus_labels (addresses,dus_labels_a);
				
				// ... new
					
				// extracting ...	
				#! (main_library_instance_i,dl_client_state)
					= dl_client_state!cs_main_library_instance_i;	
				#! main_library_instance_i
					= fromJust main_library_instance_i;
				
				//
				#! (do_dump_dynamic,dl_client_state)
					= dl_client_state!do_dump_dynamic;
					
				#! ((b,ad),dl_client_state,s,io)
					= case do_dump_dynamic of {
						_ //False
							-> app_state_with_proper_names_table (link_to_graph_conversion [ModuleUnknown module_name symbol_name]) dl_client_state s io;
						_
							-> abort "ssks";
					};
				
				# symbol_addresses
					= [(hd ad):[ a \\ a <-: addresses ]];
					
				# conversion_dus_label
					= { default_elem &
						dusl_label_name				= symbol_name
					,	dusl_library_instance_i		= main_library_instance_i
					,	dusl_linked					= False
					};
				# dus_labels
					= [conversion_dus_label:[dus_label \\ dus_label <-: dus_labels]];
				#! symbol_addresses
					= symbol_addresses  //<<- ("hallo",hd ad,symbol_addresses,dus_labels);
				-> (dus_labels,(b,symbol_addresses,dl_client_state,s,io)); 
			_
				-> ([],NewLinkerFunction2a False unknown_modules_or_symbols dl_client_state s io);
		};

	#! (dl_client_state,io)
		= case first_time of {
			False
				-> (dl_client_state,SendAddressToClient client_id (/* toString DYN_OK,*/ id,symbol_addresses) io);
			True
/*
				// get info about the library instances used by the dynamic
				# (di_library_instance_to_library_index,dl_client_state)
					= dl_client_state!cs_dynamic_info.[id].di_library_instance_to_library_index;
				# (di_library_index_to_library_name,dl_client_state)
					= dl_client_state!cs_dynamic_info.[id].di_library_index_to_library_name;
					
					
				| F ("di_library_instance_to_library_index: " +++ toString (size di_library_instance_to_library_index)) True 
					
				# library_instance_runtime_ids	// indexed by RunTimeID(diskID) to obtain library instance id
					= force_unboxed_int_array (createArray (size di_library_instance_to_library_index) (-1));
			
				# (library_instance_runtime_ids,_,dl_client_state)
					= mapAiSt convert_string_id_to_runtime_id_for_a_library_instance di_library_instance_to_library_index (library_instance_runtime_ids,di_library_index_to_library_name,dl_client_state);


				// ComputeDescAddress still contains diskIDs instead of real RunTimeIDs, so the conversion tabe
				# dl_client_state
					= { dl_client_state & cs_dynamic_info.[id].di_disk_id_to_library_instance_i = library_instance_runtime_ids };

				// printing					
				#! dl_client_state
					= AddMessage (Verbose "References to type-libraries i.e. type tables") dl_client_state;
				#! (type_tables,dl_client_state)
					= get_type_tables dl_client_state;
				#! (type_tables,dl_client_state)
					= loopAfill print_library_name type_tables dl_client_state;
				#! dl_client_state
					= { dl_client_state & cs_type_tables = type_tables };

*/
				#! (library_instance_runtime_ids,dl_client_state)
					= dl_client_state!cs_dynamic_info.[id].di_disk_id_to_library_instance_i;
				#! (di_disk_to_rt_dynamic_indices,dl_client_state)
					= dl_client_state!cs_dynamic_info.[id].di_disk_to_rt_dynamic_indices;
				
				#! msg
					= (encode library_instance_runtime_ids,
					// lazy dynamics...
					encode di_disk_to_rt_dynamic_indices,
					// ... lazy dynamics
					id,symbol_addresses);
				-> (dl_client_state,SendAddressToClient client_id msg io);
		};

	// check for errors		
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| /*F ("XXX" +++ Pl unknown_modules_or_symbols "")*/ not ok
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);

	// verbose	
	#! messages
		= foldl2 produce_verbose_output2 [] dus_labels symbol_addresses;
		
		
/*
				# conversion_dus_label
					= { default_elem &
						dusl_label_name				= symbol_name
					,	dusl_library_instance_i		= main_library_instance_i
					,	dusl_type_equivalence_class_with_implementation	= False
					};
*/	
	#! dl_client_state
		= SetLinkerMessages messages dl_client_state ;
	// end

	
	#! (ok,dl_client_state)
		= checkTypeEquivalentClasses dl_client_state;
	| not ok
		= abort "error";


	= (not ok,client_id,AddToDLServerState dl_client_state s,io);
where {
	fill_addresses_and_dus_labels:: !u:DusLabel !*(!*{#Int},!*{#DusLabel}) -> (!*{#Int},!*{#DusLabel});
	fill_addresses_and_dus_labels dus_label=:{dusl_linked,dusl_ith_address,dusl_address} (addresses,dus_labels_a)
//		| dusl_ith_address < 0 || dusl_address <= 0 || not dusl_linked <<- (dus_label,dusl_linked)
//			= abort "fill_addresses_and_dus_labels; internal error";
			
		#! addresses
			= { addresses & [dusl_ith_address] = dusl_address };
		#! dus_labels_a
			= { dus_labels_a & [dusl_ith_address] = dus_label };
		= (addresses,dus_labels_a);
	
	// computes which disk libraries are needed to build the current block
	compute_used_libraries_in_current_block block_i _ {bitset,prefix_set_and_string_ptr,dus_library_instance_nr_on_disk} (ith_address,used_disk_libraries)
		#! (prefixes,_,_)
			= determine_prefixes3 prefix_set_and_string_ptr;

		#! ith_address
			= if (fst (isBitSetMember bitset block_i)) (ith_address + length prefixes) ith_address;
		#! used_disk_libraries
			= AddBitSet used_disk_libraries dus_library_instance_nr_on_disk;
			
		= (ith_address,used_disk_libraries);
			
	
			
	
	
	
	link_to_graph_conversion s1 dl_client_state s io
		#! (b,ad,dl_client_state,s,io)
			= NewLinkerFunction2a False s1 dl_client_state s io;
		| length ad <> 1
			= abort "ComputeDescAddressTable2; internal error";
		= ((b,ad),dl_client_state,s,io);

/*
HIERO

*/	
	// ............

/*	
	compute_label_addresses_for_each_library_separately library_instance_i (addresses,dus_labels,dl_client_state)
		#! (dus_labels,(addresses,dl_client_state))
			= mapAeiauSt compute_addresses_for_labels dus_labels (addresses,dl_client_state);
		= (addresses,dus_labels,dl_client_state);
	where {
		compute_addresses_for_labels {dusl_label_name,dusl_library_instance_i} i dus_labels (addresses,dl_client_state)
			= abort "compute_addresses_for_labels";
	};
		
	// step 1: ensure library is loaded i.e. each symbol is identified by a (symbol_i,file_i)-pair
	load_library {dusl_linked=True} (dl_client_state,s,io)
		// need not initialize library_instance_i because it has already been initialize. It contains
		// the label name to be linked.
		= (dl_client_state,s,io);


	load_library {dusl_label_name,dusl_library_instance_i} (dl_client_state,s,io)
		#! (li_library_initialized,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[dusl_library_instance_i].li_library_initialized;
		| li_library_initialized
			// The NamesTable in LibraryInstance, the app_linker_state in DLClientState have already been
			// initialized.
			= (dl_client_state,s,io);
			
			// hier moet de library geladen worden.	
			= abort "uninitialized";

	// step 2: for each newly selected implementation type
	//		   replace reference to constructors of the implementation type by an indirection to the proper
	//		   constructor of the implementation type.
	
	// step 3: 
	// mark_used_modules
	


	compute_label_address {dusl_label_name,dusl_library_instance_i} (dl_client_state,s,io)
		= abort "compute_label_address";
*/
	
/*

mapAiSt f a s :== map_a_st 0 (size a) f a s
where {
	map_a_st i limit f a s
		| i == limit
			= s;
			= map_a_st (inc i) limit f a (f i a.[i] s);
}; 
			
/*
	#! (library_instance_i,_,dl_client_state)
		= RegisterLibrary main_code_type_lib dl_client_state;
*/			


*/
	

	lookup_library_id :: !Int (!*{#Int},!{#{String}},!*DLClientState) -> (!*{#Int},!{#{String}},!*DLClientState);
	lookup_library_id index (type_table_id_array,library_names,dl_client_state)
		# (type_table_id,dl_client_state)
			= AddReferenceToTypeTable library_names.[index] dl_client_state;
		# type_table_id_array
			= { type_table_id_array & [index] = type_table_id };
		= (type_table_id_array,library_names,dl_client_state);
	

		
	Pl [] s
		= s;
	Pl [ModuleUnknown module_name symbol_name:xs] s
		= Pl xs ("(" +++ module_name +++ "," +++ symbol_name +++ ")\n " +++ s);
/*
	get_tables_from_dynamic args file_name id dl_client_state io
		#! dynamic_access
			= case (size args) of {
				ComputeDescAddressTable2_n_args
					-> "FILE";		// file containing dynamic is read by dynamic rts
				ComputeDescAddressTable2_n_copy_request_args 
					-> "VIEW";		// view passed by the rts is read by dynamic rts
			};
		#! dl_client_state
 			= AddMessage (Verbose ("dynamic access: " +++ dynamic_access)) dl_client_state;
		| size args == ComputeDescAddressTable2_n_args
			// open dynamic
			#! (ok,dynamic_header,file,io)
				= open_dynamic_as_binary file_name io;
			| not ok
				#! (_,io)
					= close_dynamic_as_binary file io;
				#! msg
					= "could not open dynamic '" +++ file_name +++ "'";
				#! dl_client_state
					= AddMessage (LinkerError msg) dl_client_state;
				= (0,dl_client_state,io);

			# (file,id,dl_client_state,io)
				= read_from_dynamic file dl_client_state io dynamic_header;
			# (_,io)
				= close_dynamic_as_binary file io;
//			# dl_client_state
//				= { dl_client_state & cs_dynamic_info.[id].di_version = toVersion dynamic_header.version_number };

			= (id,dl_client_state,io);
		| size args == ComputeDescAddressTable2_n_copy_request_args
			# file_mapping_handle
				= toInt args.[4];
			# s_buffer
				= toInt args.[5];

			# (ok,file)
				= OpenExistingSharedBuffer file_mapping_handle s_buffer
			| not ok
				= abort "get_tables_from_dynamic: OpenExistingSharedBuffer failed";
				
			# (ok,dynamic_header,file)
				= read_dynamic_header file;
			| not ok
				= abort "get_tables_from_dynamic: error reading dynamic header";
				

			# (file,id,dl_client_state,io)
				= read_from_dynamic file dl_client_state io dynamic_header;
					
			| CloseExistingSharedBuffer file
			// version_number/ 	#! (version,dl_client_state) 
//		= dl_client_state!cs_dynamic_info.[id].di_version;
//				# dl_client_state
//					= { dl_client_state & cs_dynamic_info.[id].di_version = toVersion dynamic_header.version_number };
				= (id,dl_client_state,io);
				= abort "unreachable";
	where {
		read_from_dynamic :: !*f !*DLClientState !.a !.DynamicHeader -> *(!*f,!Int,!*DLClientState,!.a) | BinaryDynamicIO f;
		read_from_dynamic file dl_client_state io dynamic_header
			// read descriptor usage set table
			#! (ok,descriptor_usage_table,file)
				= read_descriptor_usage_table_from_dynamic dynamic_header file;
			| not ok
				#! msg
					= "could not read descriptor usage table '" +++ file_name +++ "'";
				#! dl_client_state
					= AddMessage (LinkerError msg) dl_client_state;
				= (file,0,dl_client_state,io);
			
			// read string table
			#! (ok,stringtable,file)
				= read_string_table_from_dynamic dynamic_header file;
			#! dl_client_state
				= case ok of {
					True
						-> dl_client_state;
					False
						#! msg
							= "could not read string table from '" +++ file_name +++ "'";
						-> AddMessage (LinkerError msg) dl_client_state;
				};
				
			// read dynamic rts info
			#! (lib_link,dl_client_state)
				= dl_client_state!lib_link;
			#! (ok2,dynamic_info,file)
				= case lib_link of {
						True	-> read_rts_info_from_dynamic dynamic_header file;
						_		-> (True,default_dynamic_info,file);
				};
				
			#! dl_client_state
				= case ok2 of {
					True
						-> dl_client_state;
					False
						#! msg
							= "could not read dynamic rts info from '" +++ file_name +++ "'";
						-> AddMessage (LinkerError msg) dl_client_state;
				};
				// DynamicInfo
				
				
/*
			// update dl_client_state
			#! dl_client_state
				= { dl_client_state &
					stringtable				= stringtable
				,	descriptor_usage_table	= descriptor_usage_table
				,	version					= toVersion dynamic_header.version_number
				};
*/
			# dynamic_info
				= { dynamic_info &
					di_string_table				= stringtable
				,	di_descriptor_usage_table	= descriptor_usage_table
				,	di_version					= toVersion dynamic_header.version_number
				,	di_file_name				= file_name
				};
			| dynamic_header.version_number == 0 // <<- ("read_from_dynamic", dynamic_header.version_number)
				= abort " zero";
			# dl_client_state
				= UpdateDynamicInfo id dynamic_info dl_client_state
			= (file,id,dl_client_state,io);
	};

*/		
};

/*
compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class dus_label/*=:{dusl_linked=True}*/ i dus_labels (addresses,dl_client_state)
	#! (label_address,dus_labels,(addresses,dl_client_state)) 
		= compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class2 dus_label i dus_labels (addresses,dl_client_state);
	#! addresses
		= { addresses & [i] = label_address };
	= (dus_labels,(addresses,dl_client_state));

compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class _ _ dus_labels s
	= (dus_labels,s);
*/

compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class3 :: !DusLabel !*DLClientState -> (!DusLabel,*DLClientState);
compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class3 dus_label/*=:{dusl_linked=True}*/ dl_client_state
	#! (label_address,dl_client_state)
		= compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class2 dus_label /*(-89)*/ /*[]*/ dl_client_state;
	#! dus_label
		= { dus_label &
			dusl_address = label_address
		};
	= (dus_label,dl_client_state);	
compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class3 dus_label dl_client_state
	= (dus_label,dl_client_state);

compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class2 :: !DusLabel !*DLClientState -> *(Int,*DLClientState);
compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class2 {dusl_label_name,dusl_library_instance_i} dl_client_state
	#! (maybe_label,dl_client_state)
		= findLabel dusl_label_name dusl_library_instance_i dl_client_state;
	| isNothing maybe_label
		= abort ("compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class; internal error; label should exist '" +++ dusl_label_name +++ "'");
		
	#! (file_n,symbol_n)
		= fromJust maybe_label;
	#! (maybe_label_address,dl_client_state)
		= isLabelImplemented file_n symbol_n dl_client_state;
	| isNothing maybe_label_address
		= abort ("compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class; internal error; label should exist (unmarked) '" +++ dusl_label_name +++ "'" +++ toString dusl_library_instance_i);
		
	= (fromJust maybe_label_address,dl_client_state);


N_SECTIONS_IN_MEMORY	:== 2;

// get address of the graph to string function
GetGraphToStringFunction :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
GetGraphToStringFunction client_id [label_names_encoded_in_msg] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| F "GetGraphToStringFunction" not client_exists
		= internal_error "GetGraphToStringFunction (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "GetGraphToStringFunction") dl_client_state;
		
		
	#! (lib_link,dl_client_state)
		= dl_client_state!lib_link;
		
	#! (l,graph_to_string,dl_client_state,s,io) 
		= case lib_link of {
			False
				// by default use the latest conversion function; when using unique dynamics this should
				// be changed to use the same conversion function as has already been used.
				#! (ok,latest_version,dl_client_state,s)
					= eager_write_version dl_client_state s;
			
				#! (dlink_dir,s)
					= GetDynamicLinkerDirectory s;
				#! module_name
					= dlink_dir +++ "\\" +++ copy_graph_to_string +++ "_" +++ (toFileNameSubString latest_version) +++ ".obj";
				#! symbol_name
					= "e____SystemDynamic__d" +++ copy__graph__to__string +++ "__" +++ toFileNameSubString latest_version;		
				#! graph_to_string
					= [ModuleUnknown module_name symbol_name];
					
				// copy of AddDescriptors ...				
				// search, link and load descriptors
				#! lib_link = dl_client_state.lib_link;
				#! (linked,l,dl_client_state,s,io)
					= NewLinkerFunction2a (not lib_link) graph_to_string dl_client_state s io;
				-> (l,graph_to_string,dl_client_state,s,io);
			True
				// The conversion-functions are shared among all library instances. The Clean-data structures used within
				// these functions may only have a single implementation.
				#! ({tafge_version=latest_version,tafge_conversion},tfge_index,dl_client_state)
					= get_from_graph_function_address2 Nothing dl_client_state;
				| isJust tafge_conversion <<- tafge_conversion
					// conversion-functions have already been linked. Re-use these functions
					#! (dlink_dir,s)
						= GetDynamicLinkerDirectory s;
					#! module_name
						= dlink_dir +++ "\\" +++ copy_graph_to_string +++ "_" +++ (toFileNameSubString latest_version) +++ ".obj";
					#! symbol_name
						= "e____SystemDynamic__d" +++ copy__graph__to__string +++ "__" +++ toFileNameSubString latest_version;
					#! graph_to_string
						= [ModuleUnknown module_name symbol_name];
					-> ([fromJust tafge_conversion],graph_to_string,dl_client_state,s,io);
					
				#! ((l,graph_to_string),dl_client_state,s,io)
					= app_state_with_proper_names_table (link_from_graph_conversion latest_version) dl_client_state s io;

				# dl_client_state
					= { dl_client_state & cs_to_and_from_graph.tafgt_from_graphs.[tfge_index].tafge_conversion = Just (hd l) };
				-> (l,graph_to_string,dl_client_state,s,io);
		};

	// check for errors		
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state;
	| not ok
		= (not ok,client_id,AddToDLServerState dl_client_state s,io);
		
	// DLClientState
	# (dl_client_state,io)
		= case lib_link of {
			True
				# (cs_n_lazy_dynamics,dl_client_state)
					= dl_client_state!cs_n_lazy_dynamics;
					
				# (msg,dl_client_state)
					= build_range_table dl_client_state;
				# encoded_l
					= EncodeClientMessage l +++ msg +++ FromIntToString cs_n_lazy_dynamics;
				# io
					= SendAddressToClient client_id encoded_l io; //abort "ok";
				-> (dl_client_state,io);
			_ 
				-> (dl_client_state,io);
		};
		
	// verbose		
	#! dl_client_state
		= SetLinkerMessages (produce_verbose_output graph_to_string l []) dl_client_state;
	= (not ok,client_id,AddToDLServerState dl_client_state s,io);
	// ... copy of AddDescriptors
where {
	build_range_table dl_client_state=:{cs_library_instances={lis_n_library_instances}}
/*
		# n_sections
			= lis_n_library_instances * N_SECTIONS_IN_MEMORY;
		# range_entries
			= createArray n_sections default_range_id_entry;
		# (_,range_entries,dl_client_state)
			= loopAst build_range_entry2 (0,range_entries,dl_client_state) lis_n_library_instances;
*/
// new ...
		# (range_entries,dl_client_state)
			= loopAst build_range_entry3 ([],dl_client_state) lis_n_library_instances;
		# range_entries
			= { range_entry \\ range_entry <- range_entries };
		# n_sections
			= size range_entries;
// ... new

		# range_id
			= {
				rid_n_range_id_entries	= n_sections
			,	rid_n_type_tables		= /* RTID_LIBRARY_INSTANCE_ID_START + */ lis_n_library_instances
			,	rid_range_entries		= range_entries
			};
			
		// rid_n_type_tables is indexed by run-time ids at run-time
			
		= (toString range_id,dl_client_state);
// new ...
	where {
		build_range_entry3 library_instance_i (range_entries,dl_client_state)
			# (li_memory_areas,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas;
			# range_entries
				= foldSt add_range_entry li_memory_areas range_entries;
			= (range_entries,dl_client_state);
		where {
			add_range_entry {ma_begin,ma_end} range_entries
				# range_id_entry
					= { default_range_id_entry &
						ride_begin_address		= ma_begin
					,	ride_end_address		= ma_end
					,	ride_type_table_i		= library_instance_i
					};
				= [range_id_entry:range_entries];
		
		};
// ... new
	
/*
		build_range_entry2 library_instance_i (range_entry_i,range_entries,dl_client_state)				
			# (li_code_begin,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_code_begin;
			# (li_code_end,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_code_end;
				
			# code_range_id_entry
				= { default_range_id_entry &
					ride_begin_address		= li_code_begin
				,	ride_end_address		= li_code_end
				,	ride_type_table_i		= library_instance_i
				} // <<- ("code",li_code_begin,li_code_end);

			# (li_data_begin1,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_data_begin;
			# (li_data_end1,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_data_end;
				
			# data_range_id_entry
				= { default_range_id_entry &
					ride_begin_address		= li_data_begin1
				,	ride_end_address		= li_data_end1
				,	ride_type_table_i		= library_instance_i
				} // <<- ("data",li_data_begin1,li_data_end1);
			# range_entries
				= { range_entries & [range_entry_i] = code_range_id_entry, [inc range_entry_i] = data_range_id_entry };
			= (range_entry_i + N_SECTIONS_IN_MEMORY,range_entries,dl_client_state);	
*/		
	};
};


link_from_graph_conversion latest_version dl_client_state s io
	// copy from above ...
	#! (dlink_dir,s)
		= GetDynamicLinkerDirectory s;
	#! module_name
		= dlink_dir +++ "\\" +++ copy_graph_to_string +++ "_" +++ (toFileNameSubString latest_version) +++ ".obj";
	#! symbol_name
		= "e____SystemDynamic__d" +++ copy__graph__to__string +++ "__" +++ toFileNameSubString latest_version;

	#! graph_to_string
		= [ModuleUnknown module_name symbol_name];
		
	// copy of AddDescriptors ...				
	// search, link and load descriptors
	#! lib_link = dl_client_state.lib_link;
	#! (linked,l,dl_client_state,s,io)
		= NewLinkerFunction2a (not lib_link) graph_to_string dl_client_state s io;
	// ... copy_from_above
	
	= ((l,graph_to_string),dl_client_state,s,io);


app_state_with_proper_names_table f dl_client_state s io
	// extracting ...	
	#! (main_library_instance_i,dl_client_state)
		= dl_client_state!cs_main_library_instance_i;	
	#! main_library_instance_i
		= fromJust main_library_instance_i;

	#! (names_table,dl_client_state)
		= acc_names_table main_library_instance_i dl_client_state;					
	#! dl_client_state
		= {dl_client_state &
			app_linker_state.namestable = names_table
		};
	// ... extracting
	
	#! (x,dl_client_state,s,io)
		= f dl_client_state s io;
		
	// restoring...
	#! (names_table,dl_client_state)
		= acc_state (\s=:{namestable} -> (namestable,{s & namestable = {}})) dl_client_state;
	#! dl_client_state
		= { dl_client_state & cs_library_instances.lis_library_instances.[main_library_instance_i].li_names_table = names_table };
	// ... restoring
	
	= (x,dl_client_state,s,io);




// ******************************************************************************************************
generate_needed_label_names3 block_i stringtable descriptor_usage_table
	# s
		= mapAiSt collect_label descriptor_usage_table ([],[]);
	= s;
where {
	collect_label _ {bitset,prefix_set_and_string_ptr} (ms,descriptor_module_table)
		// determine if descriptor is used
		| not (fst (isBitSetMember bitset block_i))
			= (ms,descriptor_module_table);
		
		// get descriptor name	
		#! (prefixes,string_offset,_)
			= determine_prefixes3 prefix_set_and_string_ptr;
			
		| length prefixes > 1 
			= abort "gen_label_names; more than one prefix should be tested";
	
		#! (descriptor_and_module_name,descriptor_module_table)
			= get_descriptor_and_module_name string_offset stringtable descriptor_module_table;

		// generate label names with proper prefixes
		#! l
			= map (\prefix -> ModuleUnknown (snd descriptor_and_module_name) (gen_label_name True descriptor_and_module_name prefix)) prefixes;
		= (ms ++ l,descriptor_module_table);
};

update_namestable_to_include_recent_type_implementations library_instance_i dl_client_state io
	// extend available array if necessary
	#! (teit_n_type_implementations,dl_client_state)
		= dl_client_state!cs_type_implementation_table.teit_n_type_implementations;
	#! (li_s_type_available,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_s_type_available;
	#! dl_client_state
		= case (teit_n_type_implementations == li_s_type_available) of {
			True
//				| True <<- "no extension"
				-> dl_client_state;
			False
//				| True <<- ("extension necessary from " +++ toString li_s_type_available +++ " to " +++ toString teit_n_type_implementations)
				#! (dl_client_state,li_type_available)
					= loopAst copy_array_element (dl_client_state,createArray teit_n_type_implementations False) li_s_type_available;
				#! dl_client_state
					= { dl_client_state & 
						cs_library_instances.lis_library_instances.[library_instance_i].li_s_type_available = teit_n_type_implementations
					,	cs_library_instances.lis_library_instances.[library_instance_i].li_type_available = li_type_available
					};
				-> dl_client_state;
		};
		
	// teit_n_type_implementations is valid
	#! dl_client_state
		= loopAst enter_type_implementation_if_necessary dl_client_state teit_n_type_implementations;
	= (dl_client_state,io);
where {
	copy_array_element i (dl_client_state,li_type_available)
		#! (ith_element,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_available.[i];
		| True <<- (ith_element)
		#! li_type_available
			= { li_type_available & [i] = ith_element };
		= (dl_client_state,li_type_available);
		
	enter_type_implementation_if_necessary type_implementation_reference dl_client_state
		#! (type_equivalent_class_available,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_available.[type_implementation_reference];
		| type_equivalent_class_available // <<- ("daar",library_instance_i,type_implementation_reference,type_equivalent_class_available)
			// The NamesTable has already been modified for the current type equivalent class.
			= dl_client_state;
			
		#! ({tei_chosen_type_implementation,tei_type_implementations},dl_client_state)
			= get_type_implementation type_implementation_reference dl_client_state;
		| isNothing tei_chosen_type_implementation 
			// Type equivalent class has not yet an implementation
			= dl_client_state;
			
		#! (chosen_library_instance_i,chosen_tio_type_reference)
			= extract_LIT_TypeReference (fromJust tei_chosen_type_implementation);
		| chosen_library_instance_i == library_instance_i || (isTypeWithoutDefinition chosen_tio_type_reference)
			// No implementation but current library implements the type
			= dl_client_state;
			
			
		#! type_implementations_to_redirect
			= filter (\(LIT_TypeReference library_instance_j _) -> library_instance_i == library_instance_j) tei_type_implementations;
		| isEmpty type_implementations_to_redirect
			// A chosen implementation for the type equivalent class but the current library (library_instance_i) has no types
			// within the type equivalent class. So it can be ignored.
			= dl_client_state;
			
			
		// The type_implementations_to_redirect belong to type equivalent class having an implementation from another library instance.
		// If there are more than the library instance has also internal type equivalences. Now the namestable should be adapted to refer
		// to the type implementation in the other library.			
		// mark type as available
		#! dl_client_state
			= { dl_client_state & 
				cs_library_instances.lis_library_instances.[library_instance_i].li_type_available.[type_implementation_reference] = True
			};
//		| True <<- ("hier",library_instance_i,type_implementation_reference)
			
		// get label names which implementent the chosen type implementation
		#! (li_chosen_type_table_i,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[chosen_library_instance_i].li_type_table_i;
		#! (chosen_type_name,labels_implementing_chosen_type,dl_client_state)
			= get_type_label_names chosen_tio_type_reference li_chosen_type_table_i  dl_client_state;
		#! (labels_implementing_chosen_type,dl_client_state)
			= mapSt (lookup_file_n_symbol_n_for_each_label chosen_library_instance_i) labels_implementing_chosen_type dl_client_state;



		#! dl_client_state
			= AddMessage (Verbose ("Patching NamesTable for '" +++ chosen_type_name +++ "'")) dl_client_state;

//		| True <<- ("***",chosen_type_name,type_implementation_reference,labels_implementing_chosen_type,tei_chosen_type_implementation 
//			, "!!!!!!!!!", type_implementations_to_redirect)
			
		// get labels for type_implementations_to_redirect
		#! (_,dl_client_state)
			= foldSt (redirect_type chosen_library_instance_i) type_implementations_to_redirect (labels_implementing_chosen_type,dl_client_state);
			
			
// home
		= dl_client_state;
	where {
		redirect_type chosen_library_instance_i (LIT_TypeReference library_instance_i tio_type_reference) (labels_implementing_chosen_type,dl_client_state)
			#! (li_type_table_i,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
			#! (_,labels_implementing_type,dl_client_state)
				= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
				
			#! dl_client_state
				= fold2St redirect_type_label labels_implementing_type labels_implementing_chosen_type dl_client_state;
			= (labels_implementing_chosen_type,dl_client_state);
		where {
			redirect_type_label refering_label chosen_label=:(file_n,symbol_n,chosen_label_name) dl_client_state
				#! msg
					= "> redirect '" +++ refering_label +++ "'<" +++ toString library_instance_i +++ "> to '"
					+++ chosen_label_name +++ "'<" +++ toString chosen_library_instance_i +++ ">";
				#! dl_client_state
					= AddMessage (Verbose msg) dl_client_state;

//				| True <<- ("redirect_type_label",refering_label,"to",chosen_label)
				#! dl_client_state
					= replaceLabel refering_label library_instance_i file_n symbol_n chosen_label_name dl_client_state;
				= dl_client_state; ///abort "redirect_type_label";
		
		
		}; // redirect_type

		lookup_file_n_symbol_n_for_each_label chosen_library_instance_i type_label_name dl_client_state
//			#! (Just (file_n,symbol_n),dl_client_state)
			#! (maybe_file_n_symbol_n,dl_client_state)
				= findLabel type_label_name chosen_library_instance_i dl_client_state;
			| isNothing maybe_file_n_symbol_n
				= abort ("alal " +++ type_label_name);
				
			#! (file_n,symbol_n)
				= fromJust maybe_file_n_symbol_n;
			= ((file_n,symbol_n,type_label_name),dl_client_state);
		
		extract_LIT_TypeReference (LIT_TypeReference library_instance_i tio_type_reference)
			= (library_instance_i,tio_type_reference);
	
	
	}
		
	
};

// disk_library_i 
link_library_instance stringtable descriptor_usage_table block_i id n_addresses disk_library_i (dus_labels,dl_client_state,s,io)
	/// from dynamic ...
	#! (stringtable,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_string_table;
	#! (descriptor_usage_table,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_descriptor_usage_table;
	// ... from dynamic
	
	#! (library_instance_i,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_disk_id_to_library_instance_i.[disk_library_i];

//	#! dl_client_state = debug "hallo" 2 dl_client_state


	#! (labels_linked,n_addresses2,labels,dl_client_state)
		= mapAiSt dus_entry_of_proper_library_instance_and_block descriptor_usage_table (True,0,[],dl_client_state);
	| n_addresses <> n_addresses2 //<<- ("-------",labels)
		= abort "link_library_instance; internal error; number of addresses should be the same";
		
	# (dl_client_state,s,io)
		= case labels_linked of {
			True
				// all current library instance labels have already been linked.
				-> (dl_client_state,s,io);
			False
/*
				#! (state,dl_client_state)
					= get_state dl_client_state;
				#! (_,state,dl_client_state,s,io)
					= LoadLibraryInstance library_instance_i (Just labels) state dl_client_state s io;
				#! dl_client_state
					 = { dl_client_state &
					 		app_linker_state	= state
					 };		
*/
//				#! (dl_client_state,s,io)
//					= u1pdate_namestable_to_include_recent_type_implementations library_instance_i dl_client_state s io;
					
					
				#! (_,dl_client_state/*,s*/,io)
					= LoadLibraryInstance_new library_instance_i (Just labels) dl_client_state /*s*/ io;

					 
				// what types have been linked in under water?
				#! (li_type_table_i,dl_client_state)
					= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
					
					
				#! (n_type_implementations,dl_client_state)
					= dl_client_state!cs_type_implementation_table.teit_n_type_implementations;
					
					// DLClientState
				
				#! (unlinked_labels_of_types,dl_client_state,s,io)
					= loopAst (enter_implicitly_linked_type_as_chosen_type_equivalent_class_implementation library_instance_i) ([],dl_client_state,s,io) n_type_implementations;
				| True <<- ("unlinked:",unlinked_labels_of_types)
					
				// If a type is eagerly linked i.e. all labels implementing the type have been linked, then 
				// the LoadLibraryInstance_new-application is unnecessary because it is guaranteed that all
				// type labels have already been linked.
				// If lazy linking of type is to be supported, the unlinked_labels_of_types might become
				// handy.
				// 
				// Note:
				// An efficiency improving technique might be to separate the actual link/relocation process
				// from the marking/module offset computation. Then all libraries required to satisfy a
				// request are linked at once.
//				#! (dl_client_state/*,s*/,io)
//					= LoadLibraryInstance_new library_instance_i (Just unlinked_labels_of_types) dl_client_state /*s*/ io;
				
				-> (dl_client_state,s,io);
		};	
	#! (new_dus_labels,dl_client_state)
		= mapSt compute_addresses_for_labels_belonging_to_an_implemented_type_equivalent_class3 labels dl_client_state;
	= (dus_labels ++ new_dus_labels,dl_client_state,s,io);
where {
	enter_implicitly_linked_type_as_chosen_type_equivalent_class_implementation library_instance_i type_implementation_i (unlinked_labels_of_types,dl_client_state,s,io)
		#! ({tei_type_implementations,tei_chosen_type_implementation},dl_client_state)
			= dl_client_state!cs_type_implementation_table.teit_type_implementations_a.[type_implementation_i];
		| isJust tei_chosen_type_implementation
			// a type has already been chosen and as a consequence also linked.
			= (unlinked_labels_of_types,dl_client_state,s,io);
			
		// determine whether the current library instance is member of the current type equivalent class (indicated by
		// library_instance_i) which has not yet an implementation. If the current library instance has multiple types
		// in the type equivalent class, then it should look also if one of these have already been linked.
		#! type_implementations
			= filter (\(LIT_TypeReference offered_library_instance_i _) -> library_instance_i == offered_library_instance_i) tei_type_implementations;
		| isEmpty type_implementations
			// the current library instance does not contain a type from the type equivalent class
			= (unlinked_labels_of_types,dl_client_state,s,io);
			
			// a linked in type equivalent class *without* the chosen type implementation being entered in the type
			// implementation table. Enter the implicitly chosen implementation type.
			#! type_implementation
				= hd type_implementations;
				
				
				/*
				// vervangen ....
			#! (li_type_table_i,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
			#! tio_type_reference
				= get_non_predefined_type type_implementation;
			#! (type_name,labels_implementing_type,dl_client_state)
				= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
				
				
			#! (implementation_is_available,dl_client_state)
				= anySt check_whether_implementation_is_available labels_implementing_type dl_client_state;
				
				// ... vervangen
				*/
			#! (implementation_is_available,dl_client_state)
				= isTypeImplemented type_implementation dl_client_state;

			| isNothing implementation_is_available				
//			| not implementation_is_available
				// the type has *not* been implicitly linked
				= (unlinked_labels_of_types,dl_client_state,s,io);
				
				#! (type_name,labels_implementing_type)
					= fromJust implementation_is_available;
				
				// ensure that the implementation of the type is loaded completely.
				#! remaining_unlinked_labels_implementing_type
					= [ {default_elem & 
							dusl_label_name = label_name
						,	dusl_library_instance_i = library_instance_i
						,	dusl_label_kind			= DSL_TYPE_EQUIVALENT_CLASS_IMPLEMENTATION
						} \\ label_name <- labels_implementing_type ];
				#! unlinked_labels_of_types
					= remaining_unlinked_labels_implementing_type ++ unlinked_labels_of_types;
					
				// make the chosen type the implementation type of the current equivalent class.
				#! (type_found,Just type_implementation_reference,dl_client_state)
					= findImplementationType type_implementation dl_client_state;
				| not type_found
					= abort "enter_implicitly_linked_type_as_chosen_type_equivalent_class_implementation; internal error";
					
				#! dl_client_state
					= enter_implementation_type_for_equivalence_class2 type_implementation_reference type_implementation dl_client_state;
					
				// print change
				#! msg
					= "type '" +++ type_name +++ "' has been implicitly linked" +++ toString type_implementation_reference 
						+++ " from library instance #" +++ toString library_instance_i;
				#! dl_client_state
					= AddMessage (Verbose msg) dl_client_state;	
					
				#! dl_client_state
					= foldSt print_type_labels labels_implementing_type dl_client_state;   
					
				#! dl_client_state
					= print_type_implementation_table dl_client_state;
				= (unlinked_labels_of_types,dl_client_state,s,io);
	where {
		print_type_labels label_name dl_client_state
			#! (Just (file_n,symbol_n),dl_client_state)
				= findLabel label_name library_instance_i dl_client_state;
				
			#! msg
				= label_name +++ "<" +++ toString library_instance_i +++ ">   (file_n,symbol_n)" +++ toString file_n +++ "," +++ toString symbol_n;
			#! dl_client_state
				= AddMessage (Verbose msg) dl_client_state;	
			= dl_client_state;
		
		// predefined types without definitions (and DynamicTemp) all come from the main library instance.
		get_non_predefined_type (LIT_TypeReference _ tio_type_ref) //=:{tio_type_without_definition=Nothing})
			= tio_type_ref;
		
		check_whether_implementation_is_available label_name dl_client_state
			#! (Just (file_n,symbol_n),dl_client_state)
				= findLabel label_name library_instance_i dl_client_state;
			#! (maybe_address,dl_client_state)
				= isLabelImplemented file_n symbol_n dl_client_state;
			= (isJust maybe_address,dl_client_state);
	};
			
			// LibraryInstanceTypeReference
/*
	loop_modules li_type_table_i library_instance_i module_i dl_client_state
		#! (tio_com_type_defs,dl_client_state)
			= dl_client_state!cs_type_tables.[li_type_table_i].tt_tio_common_defs.[module_i].tio_com_type_defs;
		#! dl_client_state
			= loopAst loop_types dl_client_state (size tio_com_type_defs);
		= dl_client_state;
	where {
		loop_types type_def_i dl_client_state
			#! (tio_type_def=:{tio_td_rhs},dl_client_state)
				= dl_client_state!cs_type_tables.[li_type_table_i].tt_tio_common_defs.[module_i].tio_com_type_defs.[type_def_i];
			#! dl_client_state
				= case tio_td_rhs of {
					TIO_SynType _
						// synonyms have no implementation
						-> dl_client_state;
					_
							
						# tio_type_reference
						= {
							tio_type_without_definition  = Nothing
						,   tio_tr_module_n    			 = module_i
						,   tio_tr_type_def_n  			 = type_def_i
						};
						// TIO_SynType
					# (l,dl_client_state)
						= get_type_label_names tio_type_reference li_type_table_i dl_client_state;
					-> dl_client_state;
/*
					| True <<- ("loop_types",l)
						-> abort "slsls";
*/
				};
			= dl_client_state;



/*
			#! (is_type_available,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].
				li_type_available.[module_i].[type_def_i];
			| is_type_available
			
			
				= abort "yep";
				= abort "not yet";
*/
	};
*/
	dus_entry_of_proper_library_instance_and_block :: .a !.DescriptorUsageEntry !*(.Bool,.Int,u:[w:DusLabel],*DLClientState) -> *(Bool,Int,v:[x:DusLabel],*DLClientState), [w <= x, u <= v];
	dus_entry_of_proper_library_instance_and_block _ dus_entry=:{bitset,prefix_set_and_string_ptr,dus_library_instance_nr_on_disk} (labels_linked,ith_address,labels,dl_client_state)
		#! is_entry_block_member
			= (fst (isBitSetMember bitset block_i));
		| not is_entry_block_member
			= (labels_linked,ith_address,labels,dl_client_state);
			
		| disk_library_i == dus_library_instance_nr_on_disk
			// same library and in the same block
			= generate_label_name ith_address labels dl_client_state;
			
			#! (prefixes,_,_)
				= determine_prefixes3 prefix_set_and_string_ptr;
			= (labels_linked,ith_address + length prefixes,labels,dl_client_state);
	where {
		generate_label_name ith_address labels dl_client_state
			// get descriptor name	
			#! (prefixes,string_offset,_)
				= determine_prefixes3 prefix_set_and_string_ptr;			
//			| length prefixes > 1 
//				= abort "gen_label_names; more than one prefix should be tested";
		
			#! descriptor_module_table
				= []; // overbodig?
			#! (descriptor_and_module_name=:(descriptor_name,module_name),descriptor_module_table)
				= get_descriptor_and_module_name string_offset stringtable descriptor_module_table;
				
			#! used_library_instances
				= NewBitSet 0; // overbodig?
			#! (dus_implementation=:{dusi_linked},_,dl_client_state)
				= determine_implementation_for_dus_entry descriptor_name module_name dus_library_instance_nr_on_disk prefix_set_and_string_ptr id used_library_instances dl_client_state;
				
			// insert prefixes
			#! (l,(ith_address,_))
				= mapSt generate_dus_label2 prefixes (ith_address,dus_implementation);
			= (labels_linked && dusi_linked,ith_address,labels ++ l,dl_client_state);
		where {
			generate_dus_label2 prefix (ith_address,dus_implementation)
				#! (dus_label,dus_implementation)
					= generate_dus_label prefix dus_implementation;
				#! dus_label
					= { dus_label &
						dusl_ith_address = ith_address
					};
				= (dus_label,(inc ith_address,dus_implementation));
		} // generate_label_name
		
	} // dus_entry_of_proper_library_instance_and_block
}
	
// in goede library en block


LoadLibraryInstance_new :: !.Int !(Maybe [.DusLabel]) !*DLClientState /*!*DLServerState*/ *(IOState *DLServerState)  -> *([Int],*DLClientState/*,*DLServerState*/,*IOState *DLServerState);
LoadLibraryInstance_new library_instance_i (Just []) dl_client_state /* s*/ io
	= ([],dl_client_state/* ,s*/,io);
LoadLibraryInstance_new library_instance_i labels_to_be_linked dl_client_state /*s*/ io
	#! (state,dl_client_state)
		= get_state dl_client_state;
	#! (q,l,state,dl_client_state/* ,s*/ ,io) 
		= LoadLibraryInstance library_instance_i labels_to_be_linked state dl_client_state /*s*/ io;
	#! dl_client_state
		 = { dl_client_state &
		 		app_linker_state	= state
		 };
	= (l,dl_client_state,/*s,*/io);


// LoadLibraryInstance :: !.Int !(Maybe [.DusLabel]) !*State !*DLClientState !*DLServerState *(IOState *DLServerState) -> *(Int,*State,*DLClientState,*DLServerState,*IOState *DLServerState);

generate_needed_label_names4 block_i stringtable descriptor_usage_table dl_client_state id
// 	# dl_client_state
//					= { dl_client_state & cs_dynamic_info.[id].di_disk_id_to_library_instance_i = library_instance_runtime_ids };

	# (n_Library_instances,dl_client_state)
		= dl_client_state!cs_library_instances.lis_n_library_instances;
	# used_library_instances
		= NewBitSet n_Library_instances;
		
// DLClientState
	# s
		= mapAiSt collect_label descriptor_usage_table ([],[],used_library_instances,dl_client_state);
	= s;
where {
	collect_label _ {bitset,prefix_set_and_string_ptr,dus_library_instance_nr_on_disk} (ms,descriptor_module_table,used_library_instances,dl_client_state)
		// each label is guaranteed to have a module and descriptor name because only the references to code from
		// the graph are collected in a dynamic. Internal code labels do not occur.
		// determine if descriptor is used
		| not (fst (isBitSetMember bitset block_i))
			= (ms,descriptor_module_table,used_library_instances,dl_client_state);
		
		// get descriptor name	
		#! (prefixes,string_offset,_)
			= determine_prefixes3 prefix_set_and_string_ptr;
			
		| length prefixes > 1 
			= abort "gen_label_names; more than one prefix should be tested";
	
		#! (descriptor_and_module_name=:(descriptor_name,module_name),descriptor_module_table)
			= get_descriptor_and_module_name string_offset stringtable descriptor_module_table;
			
		#! (dus_implementation,used_library_instances,dl_client_state)
			= determine_implementation_for_dus_entry descriptor_name module_name dus_library_instance_nr_on_disk prefix_set_and_string_ptr id used_library_instances dl_client_state;
			
			
		// insert prefixes
		#! (l,_)
			= mapSt generate_dus_label prefixes dus_implementation;
		= (ms ++ l,descriptor_module_table,used_library_instances,dl_client_state);


/*
		// generate label names with proper prefixes
		#! l
			= map (\prefix -> ModuleUnknown (snd descriptor_and_module_name) (gen_label_name True descriptor_and_module_name prefix)) prefixes;
		= (ms ++ l,descriptor_module_table,dl_client_state);
		
		*/
};

//generate_dus_label :: !Char !DusImplementation -> !DusLabel;
generate_dus_label prefix dusi=:{dusi_descriptor_name,dusi_module_name,dusi_library_instance_i,dusi_linked,dusi_label_kind}
	#! label_name
		= gen_label_name True (dusi_descriptor_name,dusi_module_name) prefix;
	#! dus_label
		= { default_elem &
			dusl_label_name				= label_name
		,	dusl_library_instance_i		= dusi_library_instance_i
		,	dusl_linked					= dusi_linked
		,	dusl_label_kind				= dusi_label_kind
		};
	= (dus_label,dusi);
		

:: DusImplementation
	= {
		dusi_descriptor_name		:: !String
	,	dusi_module_name			:: !String						
	,	dusi_library_instance_i		:: !Int							// if field below is False then library_instance_i contains/will contain the label_name, otherwise library_instance_i that contains actually contains the label.
	,	dusi_linked					:: !Bool						// label representing a constructor of a type equivalence member *with* implementation for that class
	,	dusi_label_kind				:: !DusLabelKind
	};
	
:: DusLabel
	= {
		dusl_label_name				:: !String						// label name valid in dusl_library_instance_i
	,	dusl_library_instance_i		:: !Int							// if field below is False then library_instance_i contains/will contain the label_name, otherwise library_instance_i that contains actually contains the label.
	,	dusl_linked 				:: !Bool						// label representing a constructor of a type equivalence member *with* implementation for that class
	,	dusl_label_kind				:: !DusLabelKind
	,	dusl_ith_address			:: !Int
	,	dusl_address				:: !Int
	};
	
:: DusLabelKind
	= DSL_EMPTY
	| DSL_RUNTIME_SYSTEM_LABEL
	| DSL_TYPE_EQUIVALENT_CLASS_WITH_IMPLEMENTATION
	| DSL_TYPE_EQUIVALENT_CLASS_IMPLEMENTATION
	| DSL_CLEAN_LABEL_BUT_NOT_A_TYPE
	;
	
instance DefaultElem DusLabel
where {
	default_elem
		= {
			dusl_label_name				= ""
		,	dusl_library_instance_i		= 0
		,	dusl_linked					= False
		,	dusl_label_kind				= DSL_EMPTY
		,	dusl_ith_address			= -999
		,	dusl_address				= -1

		};
};


// convert_constructor_name_to_descriptor_label_name
convert_descriptor_name_to_type_constructor_name True constructor_name
	= "_" +++ constructor_name;
convert_descriptor_name_to_type_constructor_name is_record constructor_name
	= constructor_name;

determine_implementation_for_dus_entry descriptor_name module_name dus_library_instance_nr_on_disk prefix_set_and_string_ptr id used_library_instances dl_client_state=:{cs_main_library_instance_i}
	#! (library_instance_i,dl_client_state)
		= dl_client_state!cs_dynamic_info.[id].di_disk_id_to_library_instance_i.[dus_library_instance_nr_on_disk];
	#! (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
		
		 // DLClientState
		 
//	| True  <<- ("searching",descriptor_and_module_name,library_instance_i,type_table_i)
	/*
	** :: Rec 
	** 		= { ... }
	** :: Xyz
	**		= Rec ...
	**
	** At run-time both the Rec-record constructor and the equally named constructor of type Xyz have the same descriptor. 
	** The Clean-compiler internally distinguishes between both constructors by prefixing the record constructor with an
	** underscore.
	*/
	#! descriptor_name_as_used_in_type_table
//		= if (is_record (get_prefix_set prefix_set_and_string_ptr)) ("_" +++ descriptor_name) descriptor_name;
		= convert_descriptor_name_to_type_constructor_name (is_record (get_prefix_set prefix_set_and_string_ptr)) descriptor_name;
	#! (result,dl_client_state)
		= findTypeUsingConstructorName descriptor_name_as_used_in_type_table module_name type_table_i dl_client_state;
	| isNothing result <<- ("searching",descriptor_name_as_used_in_type_table, module_name,library_instance_i, result)
		// label is not a Clean type but e.g. a closure, a function. It *cannot* be a non-Clean label (rts) because they
		// cannot occur in the datagraph. The implementation
		// comes from the current library instance except for run-time system label which should always come from
		// the main-library instance.
		| module_name == UnderscoreSystemModule
			# dus_implementation
				= { 
					dusi_descriptor_name	= descriptor_name
				,	dusi_module_name		= module_name
				,	dusi_library_instance_i	= fromJust cs_main_library_instance_i
				,	dusi_linked				= False
				,	dusi_label_kind			= DSL_RUNTIME_SYSTEM_LABEL
				};
			= (dus_implementation,used_library_instances,dl_client_state);

//			= abort "not found but a rts label";
			# dus_implementation
				= { 
					dusi_descriptor_name	= descriptor_name
				,	dusi_module_name		= module_name
				,	dusi_library_instance_i	= library_instance_i
				,	dusi_linked				= False
				,	dusi_label_kind			= DSL_CLEAN_LABEL_BUT_NOT_A_TYPE
				};
			= (dus_implementation,used_library_instances,dl_client_state);
		// <library_instance_i,descriptor_name,module_name>
		
		// Label belongs to a Clean-type			
		# (is_type_equation,type_implementation_ref,dl_client_state)
			= findImplementationType (LIT_TypeReference library_instance_i (fromJust result)) dl_client_state;
		| not is_type_equation <<- (descriptor_name,module_name)
			// a Clean type without equation. The implementation of the type comes from the current library
			// instance. Possibilities:
			// (KAN NIET) - rts-label	-> use rts-label from main library_instance_i
			// - otherwise	-> use labels from library instance i
			# dus_implementation
				= { 
					dusi_descriptor_name	= descriptor_name
				,	dusi_module_name		= module_name
				,	dusi_library_instance_i	= library_instance_i
				,	dusi_linked				= False
				,	dusi_label_kind			= DSL_RUNTIME_SYSTEM_LABEL
				};
			= (dus_implementation,used_library_instances,dl_client_state);

//			= abort (descriptor_name +++ "is *not* a type equation");
			// <library_instance_i,descriptor_name,module_name>
			
			
			// Get possible implementation type
			# type_implementation_ref
				= fromJust type_implementation_ref;
			# (chosen_implementation_type,dl_client_state)
				= getImplementationType type_implementation_ref dl_client_state;

			// Clean type in equivalence class
			| isNothing chosen_implementation_type <<- ("^^^",type_implementation_ref)
				// A Clean type belong to some type equivalence class *without* implementation. The implementation
				// chosen is that of the current library instance.

				// <library_instance_i,descriptor_name,module_name>
//				#! (ok,dl_client_state)
//					= checkTypeEquivalentClass type_implementation_ref dl_client_state;
//				| not ok
//					= abort "error";
			# dus_implementation
				= { 
					dusi_descriptor_name	= descriptor_name
				,	dusi_module_name		= module_name
				,	dusi_library_instance_i	= library_instance_i
				,	dusi_linked				= False
				,	dusi_label_kind			= DSL_RUNTIME_SYSTEM_LABEL
				};
			= (dus_implementation,used_library_instances,dl_client_state);



//				= abort ("free" +++ toString library_instance_i +++ descriptor_name);
				
				// a Clean type, member of a type equivalence class and *with* implementation
				// <library_instance_i of chosen implementation type,descriptor_name,module_name of the chosen library instance>
				# (new_module_name,new_library_instance_i,dl_client_state)
					= case (fromJust chosen_implementation_type) of {
						(LIT_TypeReference library_instance_i {tio_type_without_definition=Just _})
							// an internal type
							-> (module_name,library_instance_i,dl_client_state);
						(LIT_TypeReference library_instance_i {tio_tr_module_n})
							#! (li_type_table_i,dl_client_state)
								= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
							#! (tio_module,dl_client_state)
								= dl_client_state!cs_type_tables.[li_type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_module;
							#! (string_table_i,dl_client_state)
								= dl_client_state!cs_type_tables.[li_type_table_i].tt_type_io_state.tis_string_table;
							#! module_name
								= get_name_from_string_table tio_module string_table_i;
							-> (module_name,library_instance_i,dl_client_state)
					};
					
				# dus_implementation
					= { 
						dusi_descriptor_name	= descriptor_name
					,	dusi_module_name		= new_module_name
					,	dusi_library_instance_i	= new_library_instance_i
					,	dusi_linked				= True		//
					,	dusi_label_kind			= DSL_TYPE_EQUIVALENT_CLASS_WITH_IMPLEMENTATION
					};
				= (dus_implementation,used_library_instances,dl_client_state);

/*
DSL_EMPTY
*/
/*
// generate_needed_label_names3 ({#}) :: .Int .{#Char} !{#u:DescriptorUsageEntry} -> ([.ModuleOrSymbolUnknown],{#DescriptorUsageEntry}), [
generate_needed_label_names3a block_i stringtable descriptor_usage_table

	#! (s_descriptor_usage_table,descriptor_usage_table)
		= usize descriptor_usage_table;
	#! (ms,descriptor_usage_table)
		= collect_used_label_names 0 s_descriptor_usage_table descriptor_usage_table [] [];
	= (ms,descriptor_usage_table);
//	| True
//		= abort (toString s_descriptor_usage_table); //"";
	
where {
	collect_used_label_names i s_descriptor_usage_table descriptor_usage_table descriptor_module_table ms
		| /*F ("block_i: " +++ toString block_i)*/ i == s_descriptor_usage_table
			= (ms,descriptor_usage_table);

		// determine if descriptor is used
		#! (is_element,_)
			= isBitSetMember descriptor_usage_table.[i].bitset block_i; //(block_i << 2);	
		| not is_element
			= collect_used_label_names (inc i) s_descriptor_usage_table descriptor_usage_table descriptor_module_table ms;
		
		// get descriptor name	
		#! (prefixes,string_offset,_)
			= determine_prefixes3 descriptor_usage_table.[i].prefix_set_and_string_ptr;
			
		| /*F ("string_offset: " +++ toString string_offset +++ "<<<" +++ stringtable +++ ">>>>")*/ length prefixes > 1 
			= abort "gen_label_names; more than one prefix should be tested";
	
		#! (descriptor_and_module_name,descriptor_module_table)
			= get_descriptor_and_module_name string_offset stringtable descriptor_module_table;

		// generate label names with proper prefixes
		#! l
			= map (\prefix -> ModuleUnknown (snd descriptor_and_module_name) (gen_label_name True descriptor_and_module_name prefix)) prefixes;

		= /*F ("collect_used_label_names <" +++ (fst descriptor_and_module_name) +++ ">")*/  collect_used_label_names (inc i) s_descriptor_usage_table descriptor_usage_table descriptor_module_table (ms ++ l);
} // generate_needed_label_names3
*/

import Directory;

// send by second or later instance of dynamic rts to first instance of dynamic rts
MessageFromSecondOrLaterLinker :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
MessageFromSecondOrLaterLinker client_id [cmd_line] s=:{application_path} io
	#! (found,space_index)
		= CharIndex cmd_line 0 ' ';
	| not found || cmd_line.[0] == '\"'
		= abort "MessageFromSecondOrLaterLinker: internal error";		
		= AddClient3 client_id [cmd_line % (inc space_index,dec (size cmd_line))] s io;
		
DumpDynamic :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
DumpDynamic client_id [cmd_line] s=:{application_path} io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= abort "DumpDynamic: client doesnot exist";
		
	# dl_client_state
		= AddMessage (Verbose "DumpDynamic") dl_client_state;


	#! dl_client_state		
		= { dl_client_state &
			lib_link		= True
		,	do_dump_dynamic	= True
		};
		// DLClientState
	# io
		= SendAddressToClient client_id "" io; //abort "ok";

	# s
		= AddToDLServerState dl_client_state s;
	= (False,client_id,s,io);
/*
	// initialize dl_client_state
	# state
		= AddMessage (Verbose "DumpDynamic") EmptyState;
	# dl_client_state
		= { DefaultDLClientState &
			app_linker_state	= state
		};
		
	# parsed_cmd_line
		= ParseCommandLine cmd_line;
	# new_cmd_line	
		= build_cmdline_in_addclient_format 1 (size parsed_cmd_line) parsed_cmd_line;
	
	// console or gui application
	# (path_file,_)
		= ExtractPathFileAndExtension parsed_cmd_line.[0];
	# open_console_window
		= path_file.[dec (size path_file)] == 'c';
		
	// pd_StringToPath :: !String !*env -> (!(!Bool, Path), !*env) | FileSystem env
	# ((ok,path),io)
		= pd_StringToPath parsed_cmd_line.[0] io;
	# ((error,_),io)
		= getFileInfo path io;
	| error == DoesntExist
		#! msg
			= "file '" +++ parsed_cmd_line.[0] +++ "' does not exist";
		= (True,client_id,AddToDLServerState (AddMessage (LinkerError msg) dl_client_state) s,io);
		
	#! (current_directory,file_name)
		= ExtractPathAndFile parsed_cmd_line.[0];
		
	#! (client_started,client_id,client_executable,dl_client_state,s,io)
		= StartClientApplication3 current_directory file_name open_console_window new_cmd_line dl_client_state s io;
	#! dl_client_state
		= { dl_client_state & id = client_id };
	|  not client_started
		#! msg
			= "file '" +++ client_executable +++ "' cannot be started";
		= (True,client_id,AddToDLServerState (AddMessage (LinkerError msg) dl_client_state) s,io);
		
		// openClientWindow
		# dl_client_state 
			= { dl_client_state &
//				main_code_type_lib	= fst (ExtractPathFileAndExtension parsed_cmd_line.[0])
				cs_main_library_name = fst (ExtractPathFileAndExtension parsed_cmd_line.[0])
			};
		#! s
			= AddToDLServerState dl_client_state s;
		#! (s,io)
			= openClientWindow "dumpDynamic" client_id s io;
		= (False,client_id,s,io);
*/

// commandline should look as follows:
//  libpath commandlineargs
// libpath should be an absolute, full path name to an existing .lib file.
// the commandlineargs are as is passed to the process

h :: !{#{#Char}} -> !{#{#Char}};
h i = i;

AddClient3 :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
AddClient3 client_id [cmd_line:xl] s=:{application_path} io
	// initialize dl_client_state
	# state
		= AddMessage (Verbose "AddClient3") EmptyState;
	# dl_client_state
		= { DefaultDLClientState &
			app_linker_state	= state
		};
		
	# parsed_cmd_line
		= h { arg \\ arg <- xl };
	
	// console or gui application
	# (path_file,_)
		= ExtractPathFileAndExtension parsed_cmd_line.[0];
	# open_console_window
		= path_file.[dec (size path_file)] == 'c';
		
	// pd_StringToPath :: !String !*env -> (!(!Bool, Path), !*env) | FileSystem env
	# ((ok,path),io)
		= pd_StringToPath parsed_cmd_line.[0] io;
	# ((error,_),io)
		= getFileInfo path io;
	| error == DoesntExist
		#! msg
			= "file '" +++ parsed_cmd_line.[0] +++ "' does not exist!" +++ parsed_cmd_line.[0];
		= (True,client_id,AddToDLServerState (AddMessage (LinkerError msg) dl_client_state) s,io);
		
	#! (current_directory,file_name)
		= ExtractPathAndFile parsed_cmd_line.[0];
		
	#! new_cmd_line
		= foldSt (\arg s -> s +++ " " +++ arg) (tl xl) {};
		
	#! (client_started,client_id,client_executable,dl_client_state,s,io)
		= StartClientApplication3 current_directory file_name open_console_window new_cmd_line  dl_client_state s io;
	#! dl_client_state
		= { dl_client_state & id = client_id };
	|  not client_started
		#! msg
			= "file '" +++ client_executable +++ "' cannot be started";
		= (True,client_id,AddToDLServerState (AddMessage (LinkerError msg) dl_client_state) s,io);
		
		// openClientWindow
		# dl_client_state 
			= { dl_client_state &
				cs_main_library_name = fst (ExtractPathFileAndExtension parsed_cmd_line.[0])
			};
		#! s
			= AddToDLServerState dl_client_state s;
		#! (s,io)
			= openClientWindow "<unimplemented;AddClient3>" client_id s io;
		= (False,client_id,s,io);

where {
	build_cmdline_in_addclient_format i limit cmd_line
		| i == limit
			= "";
			= cmd_line.[i] +++ (if (i == (dec limit)) "" " ") +++ (build_cmdline_in_addclient_format (inc i) limit cmd_line);
};

/*
// loads a library and replaces duplicate type implementations by a single implementation
LibInit :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
LibInit client_id _ s io
	// copy from Init
	#! (client_exists,dl_client_state,s)
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "LibInit (internal error): client not registered" client_id dl_client_state s io;
		
//	#! (main_code_type_lib,dl_client_state)
//		= dl_client_state!aux_library_states.[MainLibrary].ls_main_code_type_lib;
	# (main_code_type_lib,dl_client_state)
		= dl_client_state!cs_main_library_name;
	#! dl_client_state
		= AddMessage (Verbose ("LibInit: " +++ main_code_type_lib)) dl_client_state;
		
	#! args
		= [];
		
	// check args-argument of Init-request
	#! dl_client_state
		= case (sel_platform True False) of {
			True
				// winOS
				| not (isEmpty args) 
					#! dl_client_state
						= AddMessage (LinkerError "args argument of Init in Request.icl cannot have arguments") dl_client_state;
					-> dl_client_state;
					-> dl_client_state;
			False
				// macOS
 /*
				| length args <> 1 //isEmpty args
					#! dl_client_state
						= AddMessage (LinkerError "args argument of Init in Request.icl should have exactly one parameter") dl_client_state;
					-> dl_client_state;
					
					#! dl_client_state
						= app_pd_state (\pd_state -> {pd_state & qd_address = FromStringToInt (hd args) 0}) dl_client_state;
					-> dl_client_state;
 */
 				-> abort "Request.icl; Init (line 131) uncomment!!!";

		}

/*
	// test
	#! dl_client_state
		= AddMessage (LinkerWarning "InitialLink2 is *disabled*") dl_client_state;
	#! dl_server_state
		= s;
*/
	
//	#! (_,dl_client_state,dl_server_state,io)
//		= InitialLink2 /*options_file_name*/ {dl_client_state & initial_link = True} s io;
	#! (state,dl_client_state)
		= get_state dl_client_state;
//		= // DLClientState
	#! (start_addr,state,dl_client_state,dl_server_state,io)
		= LoadLib state { dl_client_state & lib_link = True } s io; 

//	#! dl_server_state
//		= s;

	# io
		= SendAddressToClient client_id (FromIntToString start_addr) io;
		
	# dl_client_state
		 = { dl_client_state &
		 		app_linker_state	= state
		 };
	# dl_client_state
		= AddMessage (Verbose ("####start:" +++ (hex_int start_addr))) dl_client_state;

		
	// check for errors
	#! (ok,dl_client_state)
		= IsErrorOccured {dl_client_state & initial_link = False};
		
//	| F (hex_int start_addr) True
	
	= (not ok,client_id,AddToDLServerState dl_client_state dl_server_state,/*KillClient3 client_id ok*/ io);
*/
//where {
	get_state dl_client_state=:{app_linker_state}
		= (app_linker_state,{dl_client_state & app_linker_state = EmptyState});
//}
import type_io_read;
import lib;

/*
in ReadObject:

globally:
	list of modules names with index

init:
	module_contains_type_redirections := False
	if contains_type_redirections(module_to_be_read) then
		module_contains_type_redirections := True
	
		create_an_empty_hash_table for each redirected type
			{module,prefix,constructor} names are used
			# prefixes = 7, can be less if the redirected type is taken into account
			# labels = # constructors * # prefixes
			
			An hash entry looks as follows:
			name 				:: !String
			redirection_index	:: !Int
			
			for fast filling of the hash table, the index of the module name is 
			computed which is used in further searching.
			
labelled definition:
	if hash_table_contains(labelled_definition_name) then
		isolate_prefix_in_labelled_definition_name
		
		select_the_appropriate_prefix_using_the_indirection_table_by_using_the_redirection_index
		if (isYes the_selected_prefix) then
			change_definition_into_a_reference_to_the_string_following_Yes
		else
			change_the_selected_prefix_in_the_redirection_table_to_labelled_definition_name
			
			enter_name_into_the_symbol_table
		end if
	end if 
	
	If the condition is false, then the labelled_definition_name need not be redirected.
*/

create_module_name_table :: !{#TIO_CommonDefs} !*TypeIOState -> *(.ModuleNameTable,*TypeIOState);
create_module_name_table tio_common_defs type_io_state=:{tis_string_table}
	# module_names
		= { get_name_from_string_table tio_module_index tis_string_table \\ {tio_module=tio_module_index} <-: tio_common_defs };
	# module_name_table
		= { ModuleNameTable |
			module_names		= module_names
		,	contains_dynamics	= NewBitSet (size module_names)
		};
			
	= (module_name_table,type_io_state);

import RWSDebugChoice;
build_redirection_table :: !{#TIO_CommonDefs} !*TypeIOState -> (!*RedirectionTable,ModuleNameTable,!*TypeIOState);
build_redirection_table tio_common_defs type_io_state=:{tis_equivalent_type_definitions,tis_string_table}
	# (module_name_table,type_io_state)
		= create_module_name_table tio_common_defs type_io_state;
//	# redirection_table
//		= { default_redirection_info \\ _ <-: tis_equivalent_type_definitions };

	# s_redirection_table
		= mapASt (\{partitions} n_partitions -> size partitions + n_partitions) tis_equivalent_type_definitions 0;
	# redirection_table
		= { default_redirection_info \\ _ <- [1..s_redirection_table] };
		// ExtArray

	// TEST ...
	# (s_redirection_table,redirection_table)
		= usize redirection_table;
	| /*F ("build_redirection_table: " +++ toString s_redirection_table)*/ True
		
	# (_,redirection_table,module_name_table)
		= mapASt equally_named_types tis_equivalent_type_definitions (0,redirection_table,module_name_table);
	= (redirection_table,module_name_table,type_io_state);
where {
	n_tio_common_defs
		= size tio_common_defs;
		
	equally_named_types {type_name=type_name_index,partitions=equivalent_type_definitions} s
		// equality on type definitions is defined by the class EqTypes
		= mapASt equally_considered_definitions equivalent_type_definitions s
	where {
//		equally_considered_definitions :: {#TIO_TypeReference} (!Int,!*RedirectionTable) -> (!Int,!*RedirectionTable);
		equally_considered_definitions type_definitions (ith_redirection,redirection_table,module_name_table)
			# (s_redirection_table,redirection_table)
				= usize redirection_table;
//			| F ("equally_considered_definitions: " +++ (toString ith_redirection) +++ " - " +++ toString s_redirection_table) True
				
			# (redirection_info,redirection_table)
				= replace redirection_table ith_redirection default_redirection_info;
			# redirection_info
				= { redirection_info & ri_module_names = NewBitSet n_tio_common_defs };

			# (redirection_info,module_name_table)
				= mapASt insert_indirection type_definitions (redirection_info,module_name_table);
				
			# x
				= collect_constructor_names type_definitions.[0] tio_common_defs 
			# (s_x,x)
				= usize x;

			# redirection_info
				= { redirection_info & 
					ri_constructor_infos 	= x
				,	ri_s_constructor_infos	= s_x
				};
			

			# redirection_table
				= { redirection_table & [ith_redirection] = redirection_info };
			= (inc ith_redirection,redirection_table,module_name_table);
		where {
			insert_indirection {tio_tr_module_n} (redirection_info,module_name_table)
				# redirection_info
					= AddBitSetE select_indirection_bitset update_indirection_bitset redirection_info tio_tr_module_n
				# module_name_table
					= AddBitSetE
						(\index module_name_table -> module_name_table!contains_dynamics.map.[index])
						(\elem index module_name_table -> { module_name_table & contains_dynamics.map.[index] = elem})
						module_name_table
						tio_tr_module_n
				= /*F ("adding " +++ toString tio_tr_module_n)*/ (redirection_info,module_name_table);
			where {
				select_indirection_bitset :: !Int !*RedirectionInfo -> (!Int,!*RedirectionInfo);
				select_indirection_bitset index redirection_info
					= redirection_info!ri_module_names.map.[index];

				update_indirection_bitset :: !Int !Int !*RedirectionInfo -> !*RedirectionInfo;
				update_indirection_bitset elem index redirection_info
					= { redirection_info & ri_module_names.map.[index] = elem};			
			} // insert_indirection
			
		collect_constructor_names {tio_tr_module_n,tio_tr_type_def_n} tio_common_defs
			= case tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n].tio_td_rhs of {
				TIO_AlgType defined_constructors
					# constructor_infos
						= { collect_constructor_info tio_ds_index \\ {tio_ds_index} <- defined_constructors };
					-> constructor_infos;
				};
		where {
			collect_constructor_info tio_ds_index
				# {tio_cons_symb,tio_cons_type={tio_st_args}}
					= tio_common_defs.[tio_tr_module_n].tio_com_cons_defs.[tio_ds_index];
				# is_strict_constructor
					= foldSt isStrict tio_st_args False;
				# constructor_info
					= { default_constructor_info &
						ci_name 		= get_name_from_string_table tio_cons_symb tis_string_table
					,	ci_prefix_set	= if is_strict_constructor (StrictConstructor default_strict_constructor) (NonStrictConstructor default_non_strict_constructor)
					};
				= constructor_info;
			where {
				isStrict {tio_at_annotation=TIO_AN_Strict} s = s || True;
				isStrict _								   s = s || False;
			
			
			}; // collect_constructor_info
				
		
		
		
		}; // collect_constructor_names


/*
::	TIO_AType =
	{
		tio_at_annotation		:: !TIO_Annotation
	,	tio_at_type				:: !TIO_Type
	}
				generate_prefixes_from_type (TIO_AlgType s=:[_,{tio_ds_index}:_])  //defined_symbols)
					# {tio_cons_type={tio_st_args}}
						= tio_common_defs.[tio_tr_module_n].tio_com_cons_defs.[tio_ds_index];
					= abort (toString (length s));				
:: ConstructorInfo = {
		ci_name					:: !String
	,	ci_prefixes				:: !.{#LabelPrefixes}
	};
	
:: LabelPrefixes = {
		lp_n_prefix	:: Maybe !String
	,	lp_d_prefix :: Maybe !String
	,	lp_k_prefix	:: Maybe !String
	,	lp_c_prefix	:: Maybe !String
	,	lp_t_prefix	:: Maybe !String
	,	lp_r_prefix	:: Maybe !String
	,	lp_l_prefix	:: Maybe !String
	};
*/
//		where }
		
		
			
		} // equally_considered_definitions
	} // equally_named_types	

//		type_name
//			= get_name_from_string_table type_name_index tis_string_table;
} // build_redirection_table

//1.3
//print_type_equivalence :: EquivalentTypeDef (!*State,*TypeIOState,!*{#TIO_CommonDefs}) -> *(!*State,*TypeIOState,!*{#TIO_CommonDefs});
//3.1
print_type_equivalence {type_name,partitions} (state,type_io_state=:{tis_string_table},tio_common_defs)

	# type_name
		= get_name_from_string_table type_name tis_string_table;
		
	# s
		= mapAiSt print_partitions partitions (createArray (size partitions) {});
		
	# s
		= mapAiSt (\i string s -> if (i == 0) string (s +++ ", " +++ string)) s "";
		
		
	# state
		= AddMessage (Verbose ("Type equivalence(s) for '" +++ type_name +++ "':  {" +++ s +++ "}")) state;
	= (state,type_io_state,tio_common_defs);
where {
	print_partitions :: !Int !{#TIO_TypeReference} !*{#{#Char}} -> !*{#{#Char}};
	print_partitions ith_partition partition s
		# partition_string
			= mapAiSt print_partition partition "";
		= { s & [ith_partition] = "{" +++ partition_string +++ "}" };
	where {
		print_partition i {tio_tr_module_n} s
			# module_name_string_offset
				= tio_common_defs.[tio_tr_module_n].tio_module;
			# module_name
				= get_name_from_string_table module_name_string_offset tis_string_table;
			# s 
				= if (i == 0) module_name (s +++ "," +++ module_name);
			= s; 
	}; // print_partitions
}; // print_type_equivalence

//from utilities import foldSt;
	
// used for the main library

/*
// loads both the type and code library. The redirections to be made are derived from the type table and
// imposed on the code.
LoadLib :: !*State !*DLClientState !*DLServerState !(IOState !*DLServerState) -> (!Int,!*State,!*DLClientState,!*DLServerState,!(IOState !*DLServerState));
LoadLib state dl_client_state=:{lib_link /*,main_library_state={ls_main_code_type_lib}*/} /*=:{main_code_type_lib}*/ dl_server_state io
	| True
		= abort "LoadLib: disabled";	

//	| not lib_link
//		= abort "LoadLib: you need the library approach to dynamics";
		
	# (ls_main_code_type_lib,dl_client_state)
		= dl_client_state!cs_main_library_name;

	// load type library
/*
	# ((ok,rti=:{rti_n_libraries=n_libraries,rti_n_library_symbols=n_library_symbols,rti_library_list=library_list},tio_common_defs,type_io_state,names_table),io)
		= accFiles (read_type_library ls_main_code_type_lib) io;
	| not ok
		= abort "LoadLib: cannot load {code,type}-library";
*/		
	# ((result,ok,rti=:{rti_n_libraries=n_libraries,rti_n_library_symbols=n_library_symbols,rti_library_list=library_list},tio_common_defs,type_io_state,names_table,dl_client_state),io)
		= load_type_table ls_main_code_type_lib dl_client_state io;
		

	// Print type equivalences to output window
	# (tis_equivalent_type_definitions,type_io_state)
		= type_io_state!tis_equivalent_type_definitions;
	# (state,type_io_state,tio_common_defs)
		= mapASt print_type_equivalence tis_equivalent_type_definitions (state,type_io_state,tio_common_defs);
	
	// ?
	# (redirection_table,module_name_table,type_io_state)
		= build_redirection_table tio_common_defs type_io_state
	# rs
		= { default_redirection_state &
			rs_use_redirections		= True
		,	rs_label_name_table		= createArray LABEL_NAME_TABLE_SIZE Nil
		,	rs_module_name_table	= module_name_table
		,	rs_redirection_table	= redirection_table
		};
				
	// load code library
	# code_lib_name
		= build_code_lib_name ls_main_code_type_lib;
	# ((errors, xcoff_l, names_table, n_xcoff_files,rs),io)
		= accFiles (read_code_library code_lib_name names_table rs) io;
		
	// Print redirections	
	# (rs_messages,rs)
		= rs!rs_messages;
	# state
		= foldSt (\message state -> AddMessage (Verbose message) state) (reverse rs_messages) state;
		
	// resolve symbolic references by name
	# (undefined_symbols,xcoff_l,names_table)
		= import_symbols_in_xcoff_files xcoff_l 0 [] names_table;		
	| not (isEmpty undefined_symbols)
		= abort ("LoadLib: internal error undefined_symbols should be empty" +++ (fst3 (hd undefined_symbols)));
	
	#! (n_xcoff_symbols,xcoff_l)
		= n_symbols_of_xcoff_list 0 xcoff_l;
	#! (marked_bool_a,marked_offset_a,xcoff_a)
		= create_xcoff_boolean_array n_xcoff_files n_xcoff_symbols n_libraries n_library_symbols library_list xcoff_l;

	#! main_symbol
		= sel_platform "_mainCRTStartup" "main";
			
	#! state = { state & 
	// linker tables
		n_libraries				= n_libraries
	,	n_xcoff_files 			= n_xcoff_files
	,	n_xcoff_symbols			= n_xcoff_symbols
	,	n_library_symbols		= n_library_symbols
	
	,	marked_bool_a			= marked_bool_a
	,	marked_offset_a			= marked_offset_a
	,	module_offset_a			= createArray (n_xcoff_symbols+n_library_symbols) 0
	,	xcoff_a 				= xcoff_a
	,	namestable				= names_table

	// dynamic libraries
	,	library_list 			= library_list
	, 	st_redirection_state	= rs
		};
		
	#! main_symbols
		= [SymbolUnknown  "" main_symbol];
	#! ((wii,[start_addr:_],state),io)
		= LinkUnknownSymbols main_symbols state io;
		
	# (type_table_index,dl_client_state)
		= case result of {
			(Just x)
				# cs_new_type_table
					= { 
						tt_name				= ls_main_code_type_lib
					,	tt_type_io_state	= type_io_state
					,	tt_tio_common_defs	= { x \\ x <-: tio_common_defs }
					};
				# dl_client_state
					= { dl_client_state &
						cs_type_tables = { dl_client_state.cs_type_tables & [x] = cs_new_type_table}
					};
//				-> dl_client_state;
				-> abort "LoadLib; 2nd use of same type table";
			_
				# (type_table_index,dl_client_state)
					= AddReferenceToTypeTable ls_main_code_type_lib dl_client_state;

				# new_type_table
					= { default_type_table &
//						tt_name					= ls_main_code_type_lib
						tt_type_io_state		= type_io_state
					,	tt_tio_common_defs		= { x \\ x <-: tio_common_defs }
					,	tt_n_tio_common_defs	= size tio_common_defs
					,	tt_rti					= rti
					};

				# dl_client_state
					= AddTypeTable type_table_index new_type_table dl_client_state
				-> (Just type_table_index,dl_client_state);
/*
				# (cs_type_tables,dl_client_state)
					= get_type_tables dl_client_state;

				# (s_old_cs_type_tables,cs_type_tables)
					= usize cs_type_tables;
				# new_cs_type_tables
					= copy_array 0 s_old_cs_type_tables cs_type_tables { default_type_table \\ i <- [0..s_old_cs_type_tables] };

				# cs_new_type_table
					= { 
						tt_name				= ls_main_code_type_lib
					,	tt_type_io_state	= type_io_state
					,	tt_tio_common_defs	= { x \\ x <-: tio_common_defs }
					,	tt_rti				= rti
					};

				# dl_client_state
					= { dl_client_state &
						cs_type_tables = { new_cs_type_tables & [s_old_cs_type_tables] = cs_new_type_table}
					};

				-> (Just s_old_cs_type_tables,dl_client_state);
*/
		};
		
	# ms
		= { default_memory_state &
		// Library name
			ms_library_name			= ls_main_code_type_lib
		,	ms_type_table_index		= type_table_index
			
		// run-time memory areas
		,	ms_code_begin			= wii.wii_code_start
		,	ms_code_end				= wii.wii_code_end
		,	ms_data_begin			= wii.wii_data_start
		,	ms_data_end				= wii.wii_data_end
		};
	
/*	
	# dl_client_state
		= { dl_client_state &
			cs_memory_state			=[ms:dl_client_state.cs_memory_state]
		};
*/

/*
	// fill other state info
	#! (main_library_state,dl_client_state)
		= get_library_state MainLibrary dl_client_state;
	# main_library_state
		= { main_library_state &
		// type information
			ls_type_io_state	= type_io_state
		,	ls_tio_common_defs	= { x \\ x <-: tio_common_defs }
		
		// run-time memory areas
		,	ls_code_begin		= wii.wii_code_start
		,	ls_code_end			= wii.wii_code_end
		,	ls_data_begin		= wii.wii_data_start
		,	ls_data_end			= wii.wii_data_end
		};


	#! dl_client_state 
		= { dl_client_state &
			aux_library_states	= {main_library_state}
		};
*/

	= (start_addr,state,dl_client_state,dl_server_state,io);
where {
/*
	copy_array i limit old_array new_array 
		| i == limit
			= new_array;

			# (elem,old_array)
				= replace old_array i default_type_table;	
			= copy_array (inc i) limit old_array {new_array & [i] = elem};

*/

	read_code_library code_lib_name names_table rs files 
		# (errors, xcoff_l, _, names_table, file_n, files,_,rs)
			= read_static_lib_files [code_lib_name] [] names_table 0 [] files default_rsl_state rs;
		= ((errors, xcoff_l, names_table, file_n,rs), files);

/*	
	read_type_library :: !String *Files -> *(*(Bool,RTI,.{#TIO_CommonDefs},*TypeIOState,*{!NamesTableElement}),*Files);	
	read_type_library ls_main_code_type_lib files
		# (ok,rti,tio_common_defs,type_io_state,names_table,files)
			= read_type_information (build_type_lib_name ls_main_code_type_lib) create_names_table files;
		= ((ok,rti,tio_common_defs,type_io_state,names_table),files)
*/
};
LoadLib */

load_type_table ls_main_code_type_lib dl_client_state=:{cs_type_tables} io
	# (s_cs_type_tables,cs_type_tables)
		= usize cs_type_tables;
	# (result,cs_type_tables)
		= foldSt lookup_type_table [0..dec s_cs_type_tables] (Nothing,cs_type_tables);
	# dl_client_state 
		= { dl_client_state &
			cs_type_tables	= cs_type_tables
		};
	| isJust result
		// IMPROVE: the type table is read again to fill the names table with the proper
		// information. This is just laziness.
		# ((ok,rti,tio_common_defs,type_io_state,names_table),io)
			= accFiles (read_type_library ls_main_code_type_lib) io;
//		= ((result,ok,rti,tio_common_defs,type_io_state,names_table,dl_client_state),io)			
		= abort "load_type_table: 2nd time type table is read";

		# ((ok,rti,tio_common_defs,type_io_state,names_table),io)
			= accFiles (read_type_library ls_main_code_type_lib) io;
		= ((Nothing,ok,rti,tio_common_defs,type_io_state,names_table,dl_client_state),io)
where {
	lookup_type_table i s=:(Just _,cs_type_tables)
		= s;
	lookup_type_table i s=:(_,cs_type_tables)
		# (library_name,cs_type_tables)
			= cs_type_tables![i].tt_name;
		| library_name == ls_main_code_type_lib
			= (Just i,cs_type_tables);
			= (Nothing,cs_type_tables);
};

read_type_library ls_main_code_type_lib files	:== read_type_library_new True ls_main_code_type_lib files;

// old behaviour = create_new_names_table set to True
read_type_library_new :: !Bool !String *Files -> *(*(Bool,RTI,.{#TIO_CommonDefs},*TypeIOState,*{!NamesTableElement}),*Files);	
read_type_library_new create_new_names_table ls_main_code_type_lib files
	| create_new_names_table
		# (ok,rti,tio_common_defs,type_io_state,names_table,files)
			= read_type_information (build_type_lib_name ls_main_code_type_lib) create_names_table files;
		= ((ok,rti,tio_common_defs,type_io_state,names_table),files);

		// to prevent a names table being created and filled		
		# (ok,rti,tio_common_defs,type_io_state,names_table,files)
			= read_type_information_new create_new_names_table (build_type_lib_name ls_main_code_type_lib) {} files;
		= ((ok,rti,tio_common_defs,type_io_state,names_table),files);
	

/*	
	read_type_library :: !String *Files -> *(*(Bool,RTI,.{#TIO_CommonDefs},*TypeIOState,*{!NamesTableElement}),*Files);	
	read_type_library ls_main_code_type_lib files
		# (ok,rti,tio_common_defs,type_io_state,names_table,files)
			= read_type_information (build_type_lib_name ls_main_code_type_lib) create_names_table files;
		= ((ok,rti,tio_common_defs,type_io_state,names_table),files)
*/

/*
get_library_state library_i dl_client_state=:{aux_library_states}
	# (library_i,aux_library_states)
		= get_library_i aux_library_states;
	# dl_client_state
		= { dl_client_state & aux_library_states = aux_library_states };
	= (library_i,dl_client_state);
where {
	get_library_i aux_library_states
		# (library_i,aux_library_states)
			= replace aux_library_states library_i default_library_state;
		= (library_i,aux_library_states);
};
*/

GetLibraryInfo :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
GetLibraryInfo client_id [args] s io
	= abort "GetLibraryInfo";
	
	
/*

	#! (client_exists,dl_client_state=:{lib_link},s) 
		= RemoveFromDLServerState client_id s;
	| F "GetLibraryInfo" not client_exists
		= internal_error "GetLibraryInfo (internal error): client not registered" client_id dl_client_state s io;

	| not lib_link
		= abort "LoadLib: you need the library approach to dynamics";

	#! (dl_client_state)
		= AddMessage (Verbose "GetLibraryInfo") dl_client_state;

	#! args
		= ExtractArguments '\n' 0 args [];
	#! l_args
		= length args
		
	// extract arguments
//	#! module_name	= hd args
//	#! address		= hd (
	# ([module_name,address:_])
		= args;
		
	// example
	# dl_client_state 
		= build_example dl_client_state;

	// build main library info
	# (ls_children,dl_client_state)
		= dl_client_state!aux_library_states.[MainLibrary].ls_children;
				
	# (ls_code_begin,dl_client_state)
		= dl_client_state!aux_library_states.ls_code_begin;
	# (ls_code_end,dl_client_state)
		= dl_client_state!aux_library_states.ls_code_end;
	# (ls_data_begin,dl_client_state)
		= dl_client_state!aux_library_states.ls_data_begin;
	# (ls_data_end,dl_client_state)
		= dl_client_state!aux_library_states.ls_data_end;
	# (ls_main_code_type_lib,dl_client_state)
		= dl_client_state!aux_library_states.ls_main_code_type_lib;
		
	# main_library_info
		= { LibraryInfo |
			li_code_start	= ls_code_begin
		,	li_code_end		= ls_code_end
		,	li_data_start	= ls_data_begin
		,	li_data_end		= ls_data_end
		,	li_name			= ls_main_code_type_lib
		,	li_set			= 0
		};

//	# (dl_client_state,(lib_info,string_table_size))
//		= collect_library_info dl_client_state [ child \\ child <-: ls_children ] ([main_library_info],0)
		
	| True
		= abort ("GetLibraryInfo" +++ toString (0)); //length [li_set \\ {li_set} <- lib_info ]));
/*
*/		
//	#! lib_name
//		= build_code_lib_name ls_main_code_type_lib 
		
	# ok
		= True
	= (not ok,client_id,AddToDLServerState dl_client_state s,/*KillClient3 client_id ok*/ io);
where {
	collect_library_info :: !*DLClientState ![Int] ([LibraryInfo],!Int) -> !*(!*DLClientState,(![LibraryInfo],!Int));
	collect_library_info dl_client_state [] s=:(library_infos,string_table_size)
		= (dl_client_state,s);

	collect_library_info dl_client_state [sibling:siblings] (library_infos,string_table_size)
		# (ls_code_begin,dl_client_state)
			= dl_client_state!aux_library_states.[sibling].ls_code_begin;
		# (ls_code_end,dl_client_state)
			= dl_client_state!aux_library_states.[sibling].ls_code_end;
		# (ls_data_begin,dl_client_state)
			= dl_client_state!aux_library_states.[sibling].ls_data_begin;
		# (ls_data_end,dl_client_state)
			= dl_client_state!aux_library_states.[sibling].ls_data_end;
		# (ls_main_code_type_lib,dl_client_state)
			= dl_client_state!aux_library_states.[sibling].ls_main_code_type_lib;
			
	
		# (li_set,string_table_size)
			= foldSt (\{li_name,li_set} s -> if (li_name == ls_main_code_type_lib) 
			((inc (max s li_set)) , 9) //string_table_size)
			(s, 9) //string_table_size + size ls_main_code_type_lib)
			
			) library_infos (0,string_table_size);
		# library_info
			= { LibraryInfo |
				li_code_start	= ls_code_begin
			,	li_code_end		= ls_code_end
			,	li_data_start	= ls_data_begin
			,	li_data_end		= ls_data_end
			,	li_name			= ls_main_code_type_lib
			,	li_set			= li_set
			};
			
		# (new_siblings,dl_client_state)
			= dl_client_state!aux_library_states.[sibling].ls_children;
		# siblings
			= if (size new_siblings == 0) siblings (siblings ++ [ sibling \\ sibling <-: new_siblings ]);
		= collect_library_info dl_client_state siblings ([library_info:library_infos],string_table_size);
		
	// Example
	build_example :: !*DLClientState -> *DLClientState;
	build_example dl_client_state
		# (ls_main_code_type_lib,dl_client_state)
			= dl_client_state!main_library_state.ls_main_code_type_lib;

		# level_1_a
			= { default_library_state & 
				ls_main_code_type_lib = "LibraryA"
			,	ls_code_begin		  = 0
			,	ls_code_end			  = 100
			,	ls_data_begin		  = 150
			,	ls_data_end			  = 200
			};
			
		# level_1_b // + 300
			= { default_library_state & 
				ls_main_code_type_lib = "LibraryB"
			,	ls_code_begin		  = 300
			,	ls_code_end			  = 400
			,	ls_data_begin		  = 450
			,	ls_data_end			  = 500
			
			, 	ls_children			  = {2}
			};
		# level_2
			= { default_library_state & 
				ls_main_code_type_lib = ls_main_code_type_lib
			,	ls_code_begin		  = 1000
			,	ls_code_end			  = 1400
			,	ls_data_begin		  = 1450
			,	ls_data_end			  = 1500
			};


		# dl_client_state
			= { dl_client_state & 
				main_library_state.ls_children 	= {0,1}
			,	aux_library_states				= {level_1_a,level_1_b,level_2}
			//										0			1			2
			};			
		= dl_client_state;
}
*/

GetTypeTablePath :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
GetTypeTablePath client_id [args] s io
	= abort "GetTypeTablePath";

/*
	#! (client_exists,dl_client_state=:{lib_link},s) 
		= RemoveFromDLServerState client_id s;
	| F "GetTypeTablePath" not client_exists
		= internal_error "GetTypeTablePath (internal error): client not registered" client_id dl_client_state s io;

	| not lib_link
		= abort "LoadLib: you need the library approach to dynamics";

	#! (dl_client_state)
		= AddMessage (Verbose "GetTypeTablePath") dl_client_state;

	#! args
		= ExtractArguments '\n' 0 args [];
	#! l_args
		= length args
		
	// extract arguments
//	#! module_name	= hd args
//	#! address		= hd (
	# ([module_name,address:_])
		= args;
	# address
		= toInt address
		
	
	# (type_table_path,dl_client_state)
		= get_type_table_path address dl_client_state
			
	#! io
		= SendAddressToClient client_id type_table_path io;

	# ok
		= True
	= (not ok,client_id,AddToDLServerState dl_client_state s,/*KillClient3 client_id ok*/ io);
where {
	get_type_table_path :: !Int !*DLClientState -> (!String,!*DLClientState);
	get_type_table_path address dl_client_state
		# (ls_code_begin,dl_client_state)
			= dl_client_state!main_library_state.ls_code_begin;
		# (ls_code_end,dl_client_state)
			= dl_client_state!main_library_state.ls_code_end;
		# (ls_data_begin,dl_client_state)
			= dl_client_state!main_library_state.ls_data_begin;
		# (ls_data_end,dl_client_state)
			= dl_client_state!main_library_state.ls_data_end;
			
		# (ls_main_code_type_lib,dl_client_state)
			= dl_client_state!main_library_state.ls_main_code_type_lib;

		| address_in_library_state address ls_code_begin ls_code_end ls_data_begin ls_data_end
			= (build_type_lib_name ls_main_code_type_lib,dl_client_state);
	

	address_in_library_state address ls_code_begin ls_code_end ls_data_begin ls_data_end
		= in_between ls_code_begin ls_code_end address || in_between ls_data_begin ls_data_end address
};

in_between start end address
	:== address >= start && address <= end
*/

/*
convert_library_instance_index_to_library_name i s=:(library_instances_to_library_name,library_names)
	| i == TTUT_UNUSED
		= s;
*/

	// computes from the library instances which physical libraries are being used. A physical library occurs at most once
	// in the LIBRARY STRING TABLE.
//compute_amount_of_libraries_and_instance_used library_instance_i library_instance_i_non_runtime_index s=:(library_instance_max_index,library_used,n_libraries_used,dl_client_state)


compute_amount_of_libraries_and_instance_used :: !Int !(Maybe !LibraryInstanceInfo) !*(!Int,*{#Bool},!Int,!*DLClientState) -> *(!Int,*{#Bool},!Int,!*DLClientState);

compute_amount_of_libraries_and_instance_used library_instance_i (Just {lii_encoded_library_instance=library_instance_i_non_runtime_index}) s=:(library_instance_max_index,library_used,n_libraries_used,dl_client_state)
	// library_instance_i_non_runtime_index

	| library_instance_i < RTID_LIBRARY_INSTANCE_ID_START // || library_instance_i_non_runtime_index == TTUT_UNUSED
		= s;

	// compute maximum library *instance* index
	# library_instance_max_index
		= max library_instance_max_index library_instance_i_non_runtime_index; // WASlibrary_instance_i;
		
	// get type table for current library instance
	# (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	| library_used.[type_table_i]
		= (library_instance_max_index,library_used,/* WAS inc*/  n_libraries_used,dl_client_state);
	
	# library_used
		= { library_used & [type_table_i] = True };
	= (library_instance_max_index,library_used,inc n_libraries_used,dl_client_state);
compute_amount_of_libraries_and_instance_used _ _ s
	= s;


/*
:: LibraryInstanceInfo
	= {
		lii_used_by_code				:: !Bool
	,	lii_used_by_type				:: !Bool
	,	lii_encoded_library_instance	:: !Int
	};
*/


	// computes the LIBRARY INSTANCE TABLE in library_instance_to_library_index_a and the LIBRARY STRING TABLE in
	// library_index_to_library_name_a.
/*
fill_library_arrays n_libraries_used library_instance_i library_instance_i_non_runtime_index s=:(library_name_indices,library_instance_to_library_index_a,
										library_index_to_library_name_a,free_library_index_to_library_name_index,dl_client_state)
*/

// library_instance_i_non_runtime_index
fill_library_arrays :: !Int !Int !(Maybe !LibraryInstanceInfo) *(*{Maybe !Int},*{#LibraryInstanceToLibraryIndexInfo},*{#String},.Int,*DLClientState) 
-> *(*{Maybe Int},*{#LibraryInstanceToLibraryIndexInfo},*{#String},Int,*DLClientState);
fill_library_arrays n_libraries_used library_instance_i (Just {lii_used_by_code,lii_used_by_type,lii_encoded_library_instance=library_instance_i_non_runtime_index}) 
				s=:(library_name_indices,library_instance_to_library_index_a,library_index_to_library_name_a,free_library_index_to_library_name_index,dl_client_state)
				
				/*
				
										:: !Bool
	,	lii_used_by_type				:: !Bool
*/

	| library_instance_i < RTID_LIBRARY_INSTANCE_ID_START // || library_instance_i_non_runtime_index == TTUT_UNUSED 
		= s;

	// get type table for current library instance
	# (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	| isNothing library_name_indices.[type_table_i] //<<- ("*******",library_name_indices.[type_table_i],library_instance_i,type_table_i)
		// fill library_instance_to_library_index_a with index in library_index_to_library_name_a
		# library_instance_to_library_index_a
			= { library_instance_to_library_index_a & [library_instance_i_non_runtime_index] = 
			
			{default_elem &
				litlii_index_in_di_library_index_to_library_name	= free_library_index_to_library_name_index
			,	litlii_used_by_code									= lii_used_by_code
			,	litlii_used_by_type									= lii_used_by_type
			}			
			
			};
			//free_library_index_to_library_name_index };

		// fill library_index_to_library_name_a
		# (li_library_name,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_name;
		| False <<- ("^^",li_library_name, free_library_index_to_library_name_index)
			= abort "sdkdks";
		# library_index_to_library_name_a
			= { library_index_to_library_name_a & [free_library_index_to_library_name_index] = fromJust li_library_name };

		// 
		# library_name_indices
			= { library_name_indices & [type_table_i] = Just free_library_index_to_library_name_index };
		
		//
		# free_library_index_to_library_name_index
			= inc free_library_index_to_library_name_index;
		= (library_name_indices,library_instance_to_library_index_a,library_index_to_library_name_a,free_library_index_to_library_name_index,dl_client_state)
		

		# library_index_to_library_name
			= fromJust library_name_indices.[type_table_i];

		// fill library_instance_to_library_index_a with index in library_index_to_library_name_a
		# library_instance_to_library_index_a
			= { library_instance_to_library_index_a & [library_instance_i_non_runtime_index] =

			{default_elem &
				litlii_index_in_di_library_index_to_library_name	= free_library_index_to_library_name_index
			,	litlii_used_by_code									= lii_used_by_code
			,	litlii_used_by_type									= lii_used_by_type
			}			

			};
			
			// free_library_index_to_library_name_index };

		= (library_name_indices,library_instance_to_library_index_a,library_index_to_library_name_a,free_library_index_to_library_name_index,dl_client_state);
fill_library_arrays _ _ _ s
		= s;
		
	
// Types
:: LibraryInstance1
	= UnusedLibraryInstance
	| UsedLibraryInstance !Int				// disk_library_instance_i
	| LazyLibraryInstance !Int !Int			// lazy_dynamic_index disk_library_instance_i
	;
	
:: LibraryInstanceInfo
	= {
		lii_used_by_code				:: !Bool
	,	lii_used_by_type				:: !Bool
	,	lii_encoded_library_instance	:: !Int
	};
	
instance DefaultElem LibraryInstanceInfo
where {
	default_elem
		= {
			lii_used_by_code				= False
		,	lii_used_by_type				= False
		,	lii_encoded_library_instance	= -1
		};
};

q :: !*{Maybe LibraryInstanceInfo} -> !*{Maybe LibraryInstanceInfo};
q i = i;

// send to get extra dynamic rts information
GetDynamicRTSInfo :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
GetDynamicRTSInfo client_id [arg] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| F "GetDynamicRTSInfo" not client_exists
		= internal_error "GetDynamicRTSInfo (internal error): client not registered" client_id dl_client_state s io;

	#! (dl_client_state)
		= AddMessage (Verbose "GetDynamicRTSInfo") dl_client_state;
	
	// get number of type tables
	# (type_tables,dl_client_state)
		= get_type_tables dl_client_state;
	# (n_type_tables,type_tables)
		= usize type_tables
	# dl_client_state
		= { dl_client_state & cs_type_tables = type_tables };

	// create library used
	# library_used
		= createArray n_type_tables False;
		
	// decode library instances array
	# (library_instances_a,j)
		= help_type_checker2 (from_string 0 arg);		/// maps diskids to library_instances
		
	# old_library_instances_a
		= library_instances_a;
	# xcc
		= h { if (x == ~1) ("-1") (hex_int x) \\ x <-: library_instances_a };

	# library_instances_a
		=  q { if (x == ~1) Nothing 
		(Just { default_elem &
			lii_used_by_code				= IS_CODE_LIBRARY_INSTANCE x
		,	lii_used_by_type				= IS_TYPE_LIBRARY_INSTANCE x
		,	lii_encoded_library_instance	= GET_LIBRARY_INSTANCE_I x
		})
		 \\ x <-: library_instances_a };

/*
:: LibraryInstanceInfo
	= {
		lii_used_by_code				:: !Bool
	,	lii_used_by_type				:: !Bool
	,	lii_encoded_library_instance	:: !Int
	};
*/
	| False <<- ("library_instances_a",library_instances_a,old_library_instances_a,'n',xcc)
		= abort "GetDynamicRTSInfo";

	// Shared external dynamics should be detected with MD5 as I see it now. Then dynamics can freely be moved, even
	// across different platforms. Perhaps the same for libraries.	
	# (lazy_dynamic_references,k)
		= help_type_checker4 (from_string j arg);
	
	// determine used lazy dynamics	
	# max_lazy_dynamic_index
		= mapASt (\{ldr_lazy_dynamic_index} accu -> max ldr_lazy_dynamic_index accu) lazy_dynamic_references (-1);
	# n_lazy_dynamics
		= inc max_lazy_dynamic_index;
	# lazy_dynamics_a
		= createArray n_lazy_dynamics "";
	# (lazy_dynamics_a,dl_client_state)
		= mapASt collect_lazy_dynamic_reference lazy_dynamic_references (lazy_dynamics_a,dl_client_state);
	| True <<- ("lazy",lazy_dynamic_references,"\n",lazy_dynamics_a)

	// determine used type and code libraries
	# (library_instance_max_index,_,n_libraries_used,dl_client_state)
		= mapAiSt compute_amount_of_libraries_and_instance_used library_instances_a (0,library_used,0,dl_client_state);
	# n_library_instances
		= inc library_instance_max_index; //RTID_DISKID_RENUMBER_START + (inc library_instance_max_index);
	| False <<- ("aap", n_library_instances, /* size lazy_dynamic_references,lazy_dynamic_references,*/"\n!!",library_instances_a,
				library_instance_max_index,n_libraries_used)
		= abort "lslsl";
		
	| F ("n_libraries_used" +++  toString n_libraries_used +++ " - library_instance_max_index: " +++ toString library_instance_max_index
			+++ "  - library_instances_a: " +++ toString (size library_instances_a)) False // <<- library_instances_a
		= undef;
		
	// maps a type_table_i to its index in library_name_a (temp)
	# library_name_indices
		= createArray n_type_tables Nothing;
		
	// maps a library instance to its library name; LIBRARY INSTANCE TABLE
	# library_instance_to_library_index_a
		= createArray n_library_instances default_elem;
		
	// indexed by an element from library_instance_to_library_name_a to a library name; LIBRARY STRING TABLE
	# library_index_to_library_name_a
		= { "hiervan" \\ _ <- [1..n_libraries_used] };


	// fill LIBRARY INSTANCE TABLE and LIBRARY STRING TABLE
	# (_,library_instance_to_library_index_a,library_index_to_library_name_a,_,dl_client_state)
		= mapAiSt (fill_library_arrays n_libraries_used) library_instances_a (library_name_indices,library_instance_to_library_index_a,library_index_to_library_name_a,0,dl_client_state);
				
	// -----------------------------------------------
	// Store type equations for all library instances involved
	// library_instances_a contains the used library instances for the new dynamic being created. Type equations must
	// be inserted before the first block of the new dynamic will be demanded. These equations are called *eager* type
	// equations.
	// 
	# (lis_n_library_instances,dl_client_state)
		= dl_client_state!cs_library_instances.lis_n_library_instances;
		
	// library_instance (RunTime) to library_instance (Encoded)
	// 1. type equations in library_instances_a
	// 2. type equations of build_lazy_block in lazy_dynamic_references
	//
	// collect used library *code* instances in a set
	#! used_library_instances
		= createArray lis_n_library_instances UnusedLibraryInstance;
	#! (used_library_instances,dl_client_state)
		= mapAiSt compute_used_library_instance library_instances_a (used_library_instances,dl_client_state);
			
	// collect lazy equations
	#! (used_library_instances,dl_client_state)
		= mapASt compute_lazily_used_library_instances lazy_dynamic_references (used_library_instances,dl_client_state)
//	| True <<- ("###########",used_library_instances)
//		= abort "sdds";
//		= undef;
		

	// Compute the type equations to be stored in the dynamic. The fixed avalailable types are skipped because they
	// are automatically inserted each time a new library is added. 
	#! ( n_fixed_available_types,dl_client_state)
		= dl_client_state!cs_n_fixed_available_types;
	#! (n_type_equivalent_classes,dl_client_state)
		= dl_client_state!cs_type_implementation_table.teit_n_type_implementations
	#! n_fixed_available_types
		= if (isNothing n_fixed_available_types) 0 (fromJust n_fixed_available_types);

	#! (di_disk_type_equivalent_classes,_,dl_client_state)
		= foldSt collect_type_equation [n_fixed_available_types..(dec n_type_equivalent_classes)] ([],used_library_instances,dl_client_state)
		
		
	#! di_disk_type_equivalent_classes
		= { disk_type_equivalent_class \\ disk_type_equivalent_class <- di_disk_type_equivalent_classes };
//	| False <<- ("TT",size di_disk_type_equivalent_classes,di_disk_type_equivalent_classes.[0].dtec_type_equations
//		,di_disk_type_equivalent_classes.[0].dtec_lazy_type_equations)
//		= undef;

/*
dtec_type_equations			= { type_equation \\ type_equation <- type_equations }
			,	dtec_lazy_type_equations
*/
	// collect lazy type references to type tables of library instances
	// In case of dynamic apply iff the two dynamics involved are *not* matched against
	// another variable pattern i.e. a pattern containing only type variables.
	#! lazy_type_references
		= createArray n_library_instances Nothing;
	#! (any_lazy_type_references,lazy_type_references,dl_client_state)
		= mapAiSt (collect_lazy_type_references lazy_dynamic_references) library_instances_a (False,lazy_type_references,dl_client_state);
	| any_lazy_type_references
		= undef;
//	#! lazy_type_references
//		= if any_lazy_type_references any_lazy_type_references {};
	
	// alleen aanmaken als nodig
	
	// -----------------------------------------------
	#! di
		= { default_dynamic_info &
			di_library_instance_to_library_index	= library_instance_to_library_index_a	// LIBRARY INSTANCE TABLE
		,	di_library_index_to_library_name		= library_index_to_library_name_a		// LIBRARY STRING TABLE
		,	di_disk_type_equivalent_classes			= di_disk_type_equivalent_classes
		,	di_lazy_dynamics_a						= lazy_dynamics_a
		,	di_lazy_type_reference_a				= lazy_type_references

		};
		
		// 	,	di_lazy_type_reference_a				:: !{Maybe lazy_type_references}
/*
- laziness
- li
	# library_instances_a
		=  q { if (x == ~1) Nothing 
		(Just { default_elem &
			lii_used_by_code				= IS_CODE_LIBRARY_INSTANCE x
		,	lii_used_by_type				= IS_TYPE_LIBRARY_INSTANCE x
		,	lii_encoded_library_instance	= GET_LIBRARY_INSTANCE_I x
		})
		 \\ x <-: library_instances_a };


*/

		
	// DLClientState
	#! io
		= SendAddressToClient client_id (encode di) io;

	# ok
		= True
	= (not ok,client_id,AddToDLServerState dl_client_state s,/*KillClient3 client_id ok*/ io);
where {
	// Lazy type references are the numbers of library instance occuring in RunTimeIDs
	collect_lazy_type_references :: !{#LazyDynamicReference} !Int !(Maybe LibraryInstanceInfo) (!Bool,!{Maybe !LazyTypeReference},!*DLClientState) -> (!Bool,!{Maybe LazyTypeReference},!*DLClientState);
	collect_lazy_type_references lazy_dynamic_references rt_library_instance_i (Just {lii_used_by_code=False,lii_used_by_type=True,lii_encoded_library_instance}) (_,lazy_type_references,dl_client_state)
		// rt_library_instance_i 			= ith run-time library instance
		// lii_encoded_library_instance		= ith disk library instance in main dynamic
		
		// The pattern below must always succeed because all library instances but the main library instance
		// are part of some dynamic. 
		#! (Just rt_lazy_dynamic_index,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[rt_library_instance_i].li_dynamic_index;
	
		// determine lazy dynamic index (on disk)
		#! r
			= findAi (determine_disk_lazy_dynamic_index rt_lazy_dynamic_index) lazy_dynamic_references;
		| isNothing r
			// For the time being it is assumed that a lazy type reference always refers to some
			// type table in a lazy dynamic. This need probably not be so.
			= abort "collect_lazy_type_references: internal error; lazy type references which does not reference to a type table in a lazy dynamic";
			
		// determine library instance on disk
		#! (di_disk_id_to_library_instance_i,dl_client_state)
			= dl_client_state!cs_dynamic_info.[rt_lazy_dynamic_index].di_disk_id_to_library_instance_i;
		#! maybe_disk_library_instance_i
			= findAi determine_disk_library_instance_i di_disk_id_to_library_instance_i
			
			// DLClientState
			= abort "collect_lazy_type_references: lazy dynamics are unimplemented";
			//= abort ("Yep " +++ toString ((fromJust maybe_disk_library_instance_i) + 0));
	where {
		determine_disk_lazy_dynamic_index rt_lazy_dynamic_index _ {ldr_id,ldr_lazy_dynamic_index}
			| ldr_id == rt_lazy_dynamic_index
				= Just ldr_lazy_dynamic_index;
				= Nothing;
				
		determine_disk_library_instance_i lazy_dynamic_library_instance_i lazy_dynamic_disk_instance_i
			= abort "determine_disk_library_instance_i";
	}
		
			// DLClientState
	/*
	:: LazyDynamicReference
	= { 
		ldr_id							:: !Int			// run-time id of lazy dynamic
	,	ldr_site						:: !String		// e.g. path to dynamic
	,	ldr_lazy_dynamic_index			:: !Int			// disk id for lazy dynamic (block)
	};
	*/
		
//		= abort (toString rt_lazy_dynamic_index); //abort ("collect_lazy_type_references" +++ toString rt_library_instance_i +++ " " +++ toString lii_encoded_library_instance);
	collect_lazy_type_references _ rt_library_instance_i _ s
		= s;
		
	/*
:: LazyTypeReference
	= {
		ltr_lazy_dynamic_index	:: !Int		// within main dynamic (on disk)
	,	ltr_library_instance_i	:: !Int		// relative from the lazy dynamic (on disk)
	};
	*/	
		
	collect_lazy_dynamic_reference :: LazyDynamicReference (!*{#String},!*DLClientState) -> (!*{#String},!*DLClientState);
	collect_lazy_dynamic_reference {ldr_id,ldr_lazy_dynamic_index} (lazy_dynamics_a,dl_client_state)
		#! (di_file_name,dl_client_state)
			= dl_client_state!cs_dynamic_info.[ldr_id].di_file_name;
		#! lazy_dynamics_a
			= { lazy_dynamics_a & [ldr_lazy_dynamic_index] = di_file_name };
		= (lazy_dynamics_a,dl_client_state);

	collect_type_equation :: !.Int !*([DiskTypeEquivalentClass],{y:LibraryInstance1},!*DLClientState) -> *([DiskTypeEquivalentClass],{LibraryInstance1},*DLClientState);
	collect_type_equation type_implementation_table_ref s=:(collected_type_equations,used_library_instances,dl_client_state)
		#! (tei_type_implementations,dl_client_state)
			= dl_client_state!cs_type_implementation_table.teit_type_implementations_a.[type_implementation_table_ref].tei_type_implementations;
			
		#! (n_type_equations,type_equations,n_lazy_type_equations,lazy_type_equations)
			= foldSt convert_and_split_type_equivalent_class tei_type_implementations (0,[],0,[]);
		| (n_type_equations + n_lazy_type_equations) < 2
			= (collected_type_equations,used_library_instances,dl_client_state);
		
		#! disk_type_equivalent_class
			= { default_elem &
				dtec_type_equations			= { type_equation \\ type_equation <- type_equations }
			,	dtec_lazy_type_equations	= { lazy_type_equation \\ lazy_type_equation <- lazy_type_equations }
			};
		| True <<- ("collect_type_equation",type_implementation_table_ref, length type_equations,length lazy_type_equations,tei_type_implementations, "\nused_library_instances",used_library_instances) 
		= ([disk_type_equivalent_class:collected_type_equations],used_library_instances,dl_client_state)
	where {
		convert_and_split_type_equivalent_class (LIT_TypeReference library_instance_i {tio_tr_module_n,tio_tr_type_def_n,tio_type_without_definition=Nothing}) s=:(n_type_equations,type_equations,n_lazy_type_equations,lazy_type_equations)
			= case used_library_instances.[library_instance_i] of {
				UnusedLibraryInstance
					-> s;
				UsedLibraryInstance disk_library_instance_i
					# disk_type_ref
						= DiskTypeRef {dtr_library_instance_i = disk_library_instance_i, dtr_tr_module_n = tio_tr_module_n, dtr_tr_type_def_n = tio_tr_type_def_n};
					-> (inc n_type_equations,[disk_type_ref:type_equations], n_lazy_type_equations,lazy_type_equations );
//					-> abort ("UsedLibraryInstance " +++ toString disk_library_instance_i);
					
				LazyLibraryInstance lazy_dynamic_index disk_library_instance_i
					#! lazy_disk_type_ref
						= { 
							ldtr_lazy_dynamic_index	= lazy_dynamic_index
						,	ldtr_disk_type_ref		= {dtr_library_instance_i = disk_library_instance_i, dtr_tr_module_n = tio_tr_module_n, dtr_tr_type_def_n = tio_tr_type_def_n} 
						};
					#! lazy_disk_type_ref
						= LazyDiskTypeRef lazy_disk_type_ref; 
					-> (n_type_equations,type_equations, inc n_lazy_type_equations,[lazy_disk_type_ref:lazy_type_equations] );						
//					-> abort "LazyLibraryInstance";
			};

		convert_and_split_type_equivalent_class (LIT_TypeReference library_instance_i {tio_type_without_definition=Just type_name}) s=:(n_type_equations,type_equations,n_lazy_type_equations,lazy_type_equations)
			= s; //= abort ("convert_and_split_type_equivalent_class; predefined type <" +++ type_name +++ ">");
	}

/*
:: LibraryInstanceInfo
	= {
		lii_used_by_code				:: !Bool
	,	lii_used_by_type				:: !Bool
	,	lii_encoded_library_instance	:: !Int
	};
*/

	// collect used library *code* instances in a set
	// library_instance_i_non_runtime_index2
	compute_used_library_instance :: .Int !(Maybe .LibraryInstanceInfo) !*(*{LibraryInstance1},!*DLClientState) -> (*{LibraryInstance1},!*DLClientState);
	compute_used_library_instance library_instance_i (Just {lii_used_by_code=True,lii_encoded_library_instance=library_instance_i_non_runtime_index}) (used_library_instances,dl_client_state)			
		| library_instance_i < RTID_LIBRARY_INSTANCE_ID_START // || library_instance_i_non_runtime_index == TTUT_UNUSED
			= (used_library_instances,dl_client_state);

/*			
		// test whether the reference to the library instance is only made from a RunTimeID-constructor			
		# (li_memory_areas_instance_i,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas
		| isEmpty li_memory_areas_instance_i
			// no image of the library instance has been made.
			= (used_library_instances,dl_client_state);
*/			
			// DLClientState

		#! used_library_instances
			= { used_library_instances & [library_instance_i] = UsedLibraryInstance library_instance_i_non_runtime_index };
		= (used_library_instances,dl_client_state);
	compute_used_library_instance _ _ s
		= s;
		
	compute_lazily_used_library_instances :: !.LazyDynamicReference !*(*{LibraryInstance1},!*DLClientState) -> *(*{LibraryInstance1},*DLClientState);
	compute_lazily_used_library_instances {ldr_id,ldr_lazy_dynamic_index} (used_library_instances,dl_client_state)
		#! (di_disk_id_to_library_instance_i,dl_client_state)
			= dl_client_state!cs_dynamic_info.[ldr_id].di_disk_id_to_library_instance_i;
		
		#! dl_client_state
			= dl_client_state <<- ("** ", di_disk_id_to_library_instance_i);

		#! used_library_instances
			= mapAiSt compute_lazily_used_library_instance di_disk_id_to_library_instance_i used_library_instances;
		= (used_library_instances,dl_client_state);
	where {
		compute_lazily_used_library_instance disk_library_instance_i library_instance_i used_library_instances
			| disk_library_instance_i < RTID_DISKID_RENUMBER_START || library_instance_i == TTUT_UNUSED
				= used_library_instances;
				
			#! (kind,used_library_instances)
				= used_library_instances![library_instance_i];
			| False <<- ("kind",library_instance_i,kind)
				= undef;
			#! used_library_instances
				= case kind of {
					UnusedLibraryInstance
						#! used_library_instances
							= { used_library_instances & 
								[library_instance_i] = LazyLibraryInstance ldr_lazy_dynamic_index disk_library_instance_i
							};
						-> used_library_instances;
					_
						// Library instance has already been used. If it is used by an UsedLibraryInstance,
						// then the dynamic being constructed uses an already constructed block i.e. a block
						// without build_block of another dynamic and at least some build_blocks. Because at
						// least one block has been included in the new dynamic, all the disk library instances 
						// have been converted to run-time library instances: there is no need for lazy type 
						// equations.
						-> used_library_instances <<- ("ingebruik" +++ toString library_instance_i);
				};
			= used_library_instances;
	};

	help_type_checker :: !{#Int} -> !{#Int};
	help_type_checker i = i;

	help_type_checker2 :: (!{#Int},!Int) -> (!{#Int},!Int);
	help_type_checker2 i = i;

	help_type_checker3 :: (!{#String},!Int) -> (!{#String},!Int);
	help_type_checker3 i = i;

	help_type_checker4 :: (!{#LazyDynamicReference},!Int) -> (!{#LazyDynamicReference},!Int);
	help_type_checker4 i = i;

/*
	compute_dynamic_info offset_runtime_id limit di_library_table offset di_string_table di_library_table2 dl_client_state
		| offset_runtime_id == limit
			//= abort ("#(" +++ di_string_table +++ ")"); 
			= (di_library_table,di_string_table,di_library_table2,dl_client_state);
			
		// get disk id & library name
		#! id
			= FromStringToInt arg offset_runtime_id;
		#! (tt_name,dl_client_state)	
			= dl_client_state!cs_type_tables.[id].tt_name;
		| id == TTUT_UNUSED
			= compute_dynamic_info (offset_runtime_id + 4) limit di_library_table offset di_string_table di_library_table2 dl_client_state;
			
			// an used run-time id
			#! di_library_table
				= { di_library_table & [id] = offset };
			#! (offset,di_string_table)
				= fill_di_stringtable 0 (size tt_name) tt_name offset di_string_table;
			#! di_library_table2
				= { di_library_table2 & [id] = tt_name };
			= compute_dynamic_info (offset_runtime_id + 4) limit di_library_table offset di_string_table di_library_table2 dl_client_state;
	where {
		fill_di_stringtable i limit tt_name offset di_stringtable
			| i == limit
				#! di_stringtable
					= { di_stringtable & [offset] = '\0' };
				= (inc offset,di_stringtable);
			
	//		| F (toString i +++ "  " +++ toString tt_name.[i])  True
			= fill_di_stringtable (inc i) limit tt_name (inc offset) {di_stringtable & [offset] = tt_name.[i]}; //tt_name.[i]};
	};
*/	

/*
	compute_maximum_disk_id :: !Int !Int !Int !String !*DLClientState -> !*DLClientState
	compute_maximum_disk_id offset_runtime_id limit maximum_disk_id s_stringtable dl_client_state
		| offset_runtime_id == limit
			= (maximum_disk_id,s_stringtable,dl_client_state);

		// get disk id & library name
		#! id
			= FromStringToInt arg offset_runtime_id;
		#! (tt_name,dl_client_state)	
			= dl_client_state!cs_type_tables.[id].tt_name;
		| F tt_name True	

		#! maximum_disk_id
			= if (id == TTUT_UNUSED) maximum_disk_id (max id maximum_disk_id);
		= abort ("ll" +++ toString limit); //compute_maximum_disk_id (offset_runtime_id + 4) limit maximum_disk_id (s_stringtable + inc (size tt_name)) dl_client_state;
*/

//	n_library_instance offset limit n_library_instances
//		| offset == 

}
	
// HEADER
//		- version
//		- offset/size of tables e.g. string table, DiskID (or MediaID) table
//
// STRING TABLE
// each string is zero-terminated.
//
// DISK ID TABLE (or MEDIA ID TABLE)
// array of offsets in the string table. An offset refers to a complete path
// name. In the future this may also be network addresses. The table is indexed
// by the parameter of the DiskID-constructor
//
// For data dynamics (external) type information is stored here.
//

// TODO (for writing a dynamic):
// - The encoded DISK ID-table is returned to the application by the GetDynamicRTSInfo
//   function and stored in the dynamic.
// - RunTimeID ---> DiskID which is similar to the ModuleID-case.
// - dumpDynamic should be able to display the extended format

// TODO (reading a dynamic):
// - DiskID ---> RunTimeID by generating a table which is indexed by a DiskID and then
//   delivers the RunTimeID. So DiskID occur only in encoded dynamics. The RunTimeID
//   is the index in type_table (cs_type_tables-field of DLClientState-record).

// TODO (type checking)
// - if type names match i.e. type names are equal, the following information is used 
//   to identify the proper type definition:
//		* type name
//		* referencing module name (not *defining* module name due to separate compilation)
//		* ModuleID/RunTimeID. A ModuleID is converted to a RunTimeID. The RunTimeID is then
//		  used to identify the proper type table. The dynamic rts has to check the types.

resolve_overloading :: !{#Char} -> !{#Char};
resolve_overloading i = i;

resolve_overloading2 :: [TypeReference] -> [TypeReference];
resolve_overloading2 i = i;

//import StdDynamicLowLevelInterface;
instance GetTypeTableIndex LibraryID
where {
	get_type_table_index (Address address) ms
		= get_type_table_index address ms;
	get_type_table_index (Number type_table_i) _
		= Just type_table_i
};

/*
convert_to_library_instance_type_reference library_instance_i (PredefinedType type_table_i type_name) 
	= LIT_PredefinedType library_instance_i type_name;
convert_to_library_instance_type_reference library_instance_i (TypeReference type_table_i tio_type_reference)
	= LIT_TypeReference library_instance_i tio_type_reference;
*/
convert_to_library_instance_type_reference library_instance_i (TypeTableTypeReference type_table_i tio_type_ref)
	= LIT_TypeReference library_instance_i tio_type_ref;


//
// Task:
// 1. checks type definitions in the 1st-arg list
// 2. if all type defs checks succeed, then these type (and the types they depend upon) are entered into the type implementation table
CheckAndEnterType :: [.TypeReference] (!Maybe !Int) !*DLClientState *(IOState DLServerState) -> *(Bool,*DLClientState,*IOState DLServerState);
CheckAndEnterType l library_instance_i_implements_type_equivalence_class dl_client_state io
	/*
		for each pair of types:
			- replace Address by Number if necessary
			- apply equal_types to both types
				if type definitions are equivalent then continue with next pair else quit 
				
		changes to equal_types:
			- two self-contained tio_common_defs; may require extracting info from type_io_state
			- a general type check state
				
	*/

	// pass 1: establish equivalences
	# (type_defs_are_equivalent,equivalent_type_defs,dl_client_state,io)
		= foldSt check_type_pair l (True,[],dl_client_state,io);
	# dl_client_state
		= case (type_defs_are_equivalent && not (isEmpty equivalent_type_defs)) of {
			True
				// get type implementation table and type tables
//				# (type_implementation_table,dl_client_state)
//					= get_type_implementation_table dl_client_state;
//				# (type_tables,dl_client_state)
//					= get_type_tables dl_client_state;
			
				// pass 2: generate type equations
				# dl_client_state //(/*type_implementation_table,*/ type_tables,dl_client_state)
					= foldSt generate_type_equations equivalent_type_defs dl_client_state; // (/*type_implementation_table,*/ type_tables,dl_client_state);

				// update dl_client_state
//				# dl_client_state
//					= { dl_client_state &
//						cs_type_tables					= type_tables
//					,	cs_type_implementation_table	= type_implementation_table
//					};
					
				// print results
				# dl_client_state
					= print_type_implementation_table dl_client_state;
				-> dl_client_state;
			_
				-> dl_client_state;
		};
	= (type_defs_are_equivalent,dl_client_state,io);
where {
// check_type_pair :: !.TypeReference !*(!Bool,u:[v:(x:LibraryInstanceTypeReference,w:LibraryInstanceTypeReference)],*DLClientState,*IOState *DLServerState) -> *(Bool,u:[v:(x:LibraryInstanceTypeReference,w:LibraryInstanceTypeReference)],*DLClientState,*IOState *DLServerState);
	check_type_pair {tr_type_name,tr_module_name1,tr_module_name2,tr_library1,tr_library2} (True,equivalent_types,dl_client_state,io)
		// build type references
		# (library_instance_i1,rt_type_reference1,dl_client_state,io)
			= create_type_reference tr_type_name tr_module_name1 tr_library1 dl_client_state io;
		# (library_instance_i2,rt_type_reference2,dl_client_state,io)
			= create_type_reference tr_type_name tr_module_name2 tr_library2 dl_client_state io;
			
		// check type definitions
		# (type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# (ets,dl_client_state)
			= get_ets dl_client_state;

//		| True <<- ("check_type_pair:", rt_type_reference1, rt_type_reference2)
	
			
		# (equivalent_type_defs,type_tables,ets)
			= equal_type_defs rt_type_reference1 rt_type_reference2 type_tables ets;
			
		# (ets_proven_type_equivalences,ets)
			= ets!ets_proven_type_equivalences;

		// print result
		#! type1
			= tr_module_name1 +++ toString rt_type_reference1;
		#! type2
			= tr_module_name2 +++ toString rt_type_reference2;
		
			
		#! (dl_client_state)
			= AddMessage (Verbose (tr_type_name +++ ": " +++ type1 +++ 
				(if equivalent_type_defs " == " " <> ") +++
				type2 
			)) dl_client_state;

		# dl_client_state
			= { dl_client_state & 
				cs_type_tables = type_tables
			,	cs_intra_type_equalities = ets
			 };
		
		# equivalent_type
			= (convert_to_library_instance_type_reference library_instance_i1 rt_type_reference1,
			   convert_to_library_instance_type_reference library_instance_i2 rt_type_reference2);
		= (equivalent_type_defs,[equivalent_type:equivalent_types],dl_client_state,io);
		
	check_type_pair _ s
		= s;
		
	// **
//	generate_type_equations :: !(!.LibraryInstanceTypeReference,!.LibraryInstanceTypeReference) !*(!*TypeImplementationTable,!*{#*TypeTable},!*DLClientState) -> *(!*TypeImplementationTable,!*{#*TypeTable},!*DLClientState);
	generate_type_equations (LIT_TypeReference library_instance_left_i tio_type_ref_left,LIT_TypeReference library_instance_right_i tio_type_ref_right) dl_client_state //(type_implementation_table, type_tables,dl_client_state)
		// get types table for left and right types of the above tuple
		# (type_table_left_i,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_left_i].li_type_table_i;
		# (type_table_right_i,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_right_i].li_type_table_i;
		
		// collect types
		# type_left
			= TypeTableTypeReference type_table_left_i tio_type_ref_left;
		# type_right
			= TypeTableTypeReference type_table_right_i tio_type_ref_right;
			
//		# (s_type_tables,type_tables)
//			= usize type_tables;
//		| True <<- ("s_type_tables",s_type_tables)
		# (type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# (cts=:{cts_type_dependencies,cts_type_tables=type_tables})
			= collect_types type_left type_right {default_collect_types_state & cts_type_tables = type_tables};
		# dl_client_state
			= { dl_client_state &
				cs_type_tables = type_tables
			};	
			
		# dl_client_state //(type_implementation_table)
			= foldSt add_type_implementation cts_type_dependencies dl_client_state; //type_implementation_table;
			
		//	= abort ("generate_type_equations: " +++ toString teit_n_type_implementations);
		= dl_client_state; //(/*type_implementation_table,*/ type_tables,dl_client_state);
		where {
			// TIO_TypeReference
			add_type_implementation (tio_type_ref_left,tio_type_ref_right) dl_client_state
				# left_library_instance_type_ref
					= LIT_TypeReference library_instance_left_i tio_type_ref_left;
				# right_library_instance_type_ref
					= LIT_TypeReference library_instance_right_i tio_type_ref_right;
					
				# ( /*ti_reference,/* added: */ created_new_type_equivalence_class*/ _ ,dl_client_state)
					= enter_type_equation left_library_instance_type_ref right_library_instance_type_ref dl_client_state;
				= dl_client_state;			
		};

	
	
	
	// **
};

CheckTypeDefinitions :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
CheckTypeDefinitions client_id [arg] s io
	#! (client_exists,dl_client_state,s) 
		= RemoveFromDLServerState client_id s;
	| F "CheckTypeDefinitions" not client_exists
		= internal_error "CheckTypeDefinitions (internal error): client not registered" client_id dl_client_state s io;

	# l
		= resolve_overloading2 (decode (resolve_overloading arg /* { c \\ c <-: arg}*/ ));


	#! (dl_client_state)
		= AddMessage (Verbose ("CheckTypeDefinitions" +++ toString (length l))) dl_client_state;
		
	/*
		for each pair of types:
			- replace Address by Number if necessary
			- apply equal_types to both types
				if type definitions are equivalent then continue with next pair else quit 
				
		changes to equal_types:
			- two self-contained tio_common_defs; may require extracting info from type_io_state
			- a general type check state
				
	*/
	
	#! (type_defs_are_equivalent,dl_client_state,io)
		= CheckAndEnterType l Nothing dl_client_state io;
/*
	// pass 1: establish equivalences
	# (type_defs_are_equivalent,equivalent_type_defs,dl_client_state,io)
		= foldSt check_type_pair l (True,[],dl_client_state,io);
	# dl_client_state
		= case (type_defs_are_equivalent && not (isEmpty equivalent_type_defs)) of {
			True
				// get type implementation table and type tables
				# (type_implementation_table,dl_client_state)
					= get_type_implementation_table dl_client_state;
				# (type_tables,dl_client_state)
					= get_type_tables dl_client_state;
			
				// pass 2: generate type equations
				# (type_implementation_table,type_tables,dl_client_state)
					= foldSt generate_type_equations equivalent_type_defs (type_implementation_table,type_tables,dl_client_state);

				// update dl_client_state
				# dl_client_state
					= { dl_client_state &
						cs_type_tables					= type_tables
					,	cs_type_implementation_table	= type_implementation_table
					};
					
				// print results
				# dl_client_state
					= print_type_implementation_table dl_client_state;
				-> dl_client_state;
			_
				-> dl_client_state;
		};

*/	
	// finished
	#! io
		= SendAddressToClient client_id (encode type_defs_are_equivalent) io;
	# ok
		= True
	= (not ok,client_id,AddToDLServerState dl_client_state s,/*KillClient3 client_id ok*/ io);


instance toString TypeTableTypeReference
where {
	toString (TypeTableTypeReference type_table_i _)
		= " <" +++ toString type_table_i +++ ">";
};


import type_io_equal_types;

class GetLibraryInstanceIndex a :: a !*DLClientState -> (!Int,!*DLClientState);

instance GetLibraryInstanceIndex LibraryID
where {
	GetLibraryInstanceIndex (Address address) dl_client_state
		= GetLibraryInstanceIndex address dl_client_state;
	GetLibraryInstanceIndex (Number library_instance_i) dl_client_state
		= (library_instance_i,dl_client_state);
};
	
instance GetLibraryInstanceIndex Int
where {
	GetLibraryInstanceIndex address dl_client_state
		# (lis_n_library_instances,dl_client_state)
			= dl_client_state!cs_library_instances.lis_n_library_instances

		# (result,dl_client_state)
			= findAst find_library_instance dl_client_state lis_n_library_instances;
		| isJust result
			= (fromJust result,dl_client_state);
			= abort ("GetLibraryInstanceIndex Int; unknown address: " +++ toString address);
	where {
		find_library_instance library_instance_i dl_client_state
// new ...
			#! (li_memory_areas,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas;
			#! li_memory_areas
				= filter (\{ma_begin,ma_end} -> between ma_begin address ma_end) li_memory_areas;
			| isEmpty li_memory_areas
				= (Nothing,dl_client_state);
				= (Just library_instance_i,dl_client_state);
// ... new

/* 
			# (li_data_begin,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_data_begin;
			# (li_data_end,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_data_end;
			| between li_data_begin address li_data_end
				= (Just library_instance_i,dl_client_state);
				
			# (li_code_begin,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_code_begin;
			# (li_code_end,dl_client_state)
				= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_code_end;
			| between li_code_begin address li_code_end
				= (Just library_instance_i,dl_client_state);
				
				= (Nothing,dl_client_state);	
				
*/
	}
};	

/*
instance GetTypeTableIndex LibraryID
where {
	get_type_table_index (Address address) ms
		= get_type_table_index address ms;
	get_type_table_index (Number type_table_i) _
		= Just type_table_i
};
class GetTypeTableIndex a
where {
	get_type_table_index :: a [MemoryState] -> Maybe !Int
};

*/

// predefined are treated specially. but there should be distinguished between version numbers
// create_type_reference (IOState(DLServerState),LibraryID) :: .{#Char} !{#.Char} LibraryID *DLClientState *(IOState DLServerState) -> *(.RTTypeReference,*DLClientState,*IOState DLServerState);
create_type_reference tr_type_name tr_module_name tr_library dl_client_state io		
	// determine type table number
/*
	# (cs_memory_state,dl_client_state)
		= dl_client_state!cs_memory_state;
	# type_table_i
		= fromJust (get_type_table_index tr_library cs_memory_state);
*/

	# (library_instance_i,dl_client_state)
		= GetLibraryInstanceIndex tr_library dl_client_state
	# (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;

//	| tr_module_name == PredefinedModuleName
//		= abort "create_type_reference: with or without type definition" //(library_instance_i,PredefinedType type_table_i tr_type_name,dl_client_state,io);

/*
	| tr_module_name == PredefinedModuleName
		= (library_instance_i,TypeTableTypeReference type_table_i { default_elem & tio_type_without_definition = Just tr_type_name},dl_client_state,io);
*/
//	#
//		dl_client_state!cs_library_instances.lis_library_instances.[
		// DLClientState	
		
	// ensure required type table is loaded
	# (dl_client_state,io)
//		= LoadTypeTable type_table_i dl_client_state io;
		= LoadLibraryInstanceTypeTable library_instance_i type_table_i dl_client_state io
		
	# (type_tables,dl_client_state)
		= get_type_tables dl_client_state;
		
//	| True <<- tr_type_name
	
	# (maybe_tio_type_reference,type_tables)
		= findTypeUsingTypeName tr_type_name tr_module_name type_table_i type_tables;
		
	# dl_client_state
		= { dl_client_state & 
			cs_type_tables = type_tables
		};
		
/*
	// compute type reference
	# (tt_n_tio_common_defs,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_n_tio_common_defs;
	# (tis_string_table,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_type_io_state.tis_string_table;
	# (maybe_tio_type_reference,dl_client_state)
		= findAst (lookup_defining_module type_table_i tis_string_table) dl_client_state tt_n_tio_common_defs;
	| isNothing maybe_tio_type_reference
		= abort ("create_type_reference: error; defining module not found; library may no longer exist" +++ tr_type_name +++ "  " +++ tr_module_name);
*/		
	# q = TypeTableTypeReference type_table_i (fromJust maybe_tio_type_reference);
	= (library_instance_i,q,dl_client_state,io);
//		<<- ("create_type_reference", q);

where {
//	lookup_defining_module :: !.Int !.{#Char} !.Int !*DLClientState -> *(Maybe .a,*DLClientState);
	lookup_defining_module type_table_i tis_string_table tio_common_def_i dl_client_state
		# (module_name_index,dl_client_state)
			= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_common_def_i].tio_module;
		# module_name
			= get_name_from_string_table module_name_index tis_string_table;
		| /*F ("lookup_defining_module <" +++ module_name +++ "> - <" +++ tr_module_name +++ ">")*/ module_name <> tr_module_name
			= (Nothing,dl_client_state);
			
			# (tio_com_type_defs,dl_client_state)
				= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_common_def_i].tio_com_type_defs;
			# maybe_type_name
				= findAi lookup_type_name tio_com_type_defs;
			| isNothing maybe_type_name
				= abort "create_type_reference: interal error; defining module not found";
			= (maybe_type_name,dl_client_state)
	where {
		lookup_type_name tio_com_type_def_i {tio_td_name}
			# type_name
				= get_name_from_string_table tio_td_name tis_string_table;
			| type_name <> tr_type_name
				= Nothing;
				
			# rt_type_reference
				= { default_elem & //LAST  //TIO_TypeReference |
					tio_tr_module_n		= tio_common_def_i
				,	tio_tr_type_def_n	= tio_com_type_def_i
				}
			| F ("****************" +++ type_name +++ " - " +++ toString type_table_i +++ " - " +++ toString tio_common_def_i +++ " - " +++ toString tio_com_type_def_i ) True
			= Just rt_type_reference;
	};


/*
::	TIO_TypeReference
	= {
		tio_tr_module_n		:: !Int
	,	tio_tr_type_def_n	:: !Int
	}
	
:: RTTypeReference 
	= PredefinedType !String
	| TypeReference !Int !TIO_TypeReference
	// misschien met verswie nr
*/

			
			/*




			= abort ("lookup_defining_module FOUNd <" +++ module_name +++ "> - <" +++ tr_module_name +++ ">" 
			+++ toString (fromJust ));
			*/
};
/*
//	#! q
//		= size dl_client_state.cs_type_tables.[li_type_table_i].tt_tio_common_defs.[12].tio_com_type_defs;
	#! li_type_available
		= { EmptyBitSet \\ _ <- [1..tt_n_tio_common_defs] };
	#! (li_type_available,dl_client_state)
		= loopAst (create_type_available_array li_type_table_i) (li_type_available,dl_client_state) tt_n_tio_common_defs;

*/

/*
create_type_available_array li_type_table_i tio_common_defs_module_i (li_type_available,dl_client_state)
	#! (tio_com_type_defs,dl_client_state)
		= dl_client_state!cs_type_tables.[li_type_table_i].tt_tio_common_defs.[tio_common_defs_module_i].tio_com_type_defs;
	#! li_type_available
		= { li_type_available & [tio_common_defs_module_i] = createArray (size tio_com_type_defs) False};
//	| True <<- ("muis",size tio_com_type_defs)
	= (li_type_available,dl_client_state);
*/
	
LoadLibraryInstanceTypeTable library_instance_i given_type_table_i dl_client_state=:{cs_main_library_instance_i=xx,do_dump_dynamic} io
/*DD
	| isNothing cs_main_library_instance_i
		| do_dump_dynamic
//DD			# dl_client_state 
//DD				= { dl_client_state &
//DD					cs_main_library_instance_i = Just library_instance_i
//DD				};
			= LoadLibraryInstanceTypeTable library_instance_i given_type_table_i dl_client_state io;
		
			= abort "cs_main_library_instance_i not yet set";
DD */
// do_dump_dynamic
	// first call with library_instance_i; load type table for current instance, if necessary. The if can be omitted
	// after it turns out, the if-holds always.
	#! (li_type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (dl_client_state,io)
		= LoadTypeTable (if (li_type_table_i == given_type_table_i) li_type_table_i (abort "aanname mis")) dl_client_state io;

//	#! cs_main_library_instance_i
//		= fromJust cs_main_library_instance_i;
		
	#! (li_initial_types_equivalences_entered,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_initial_types_equivalences_entered;
	| li_initial_types_equivalences_entered
		// The type table has already been loaded and the initial type equivalences have already
		// been established at the first call with the current library_instance_i.
		= (dl_client_state,io);
			
	// mark it
	#! dl_client_state
		= { dl_client_state & cs_library_instances.lis_library_instances.[library_instance_i].li_initial_types_equivalences_entered = True };


	// type available ...
	#! (tt_n_tio_common_defs,dl_client_state)
		= dl_client_state!cs_type_tables.[li_type_table_i].tt_n_tio_common_defs;
		
//	#! q
//		= size dl_client_state.cs_type_tables.[li_type_table_i].tt_tio_common_defs.[12].tio_com_type_defs;
/*
	#! li_type_available
		= { {} \\ _ <- [1..tt_n_tio_common_defs] };
	#! (li_type_available,dl_client_state)
		= loopAst (create_type_available_array li_type_table_i) (li_type_available,dl_client_state) tt_n_tio_common_defs;
*/	
	
/*
loopAst f s limit :== loopAst 0 limit f s 
where {
	loopAst i limit f s
		| i == limit
			= s;
			
			#! s
				= f i s;
			= loopAst (inc i) limit f s;
}

*/
	
		
		// NewBitSet (size dl_client_state.cs_type_tables.[li_type_table_i].tt_tio_common_defs.[module_i].tio_com_type_defs)
//	| True
//		= abort (toString q);
		
	
	// TypeTable
			

//	#! dl_client_state
//		= { dl_client_state & cs_library_instances.lis_library_instances.[library_instance_i].li_type_available = li_type_available };
	// ... type available
		
	// enter initial types representing the type-component of a dynamic (type-field in DynamicTemp)
	
// DD...
	# (n_library_instances,dl_client_state)
		= dl_client_state!cs_library_instances.lis_n_library_instances;
// ... DD
	# (dl_client_state,io)
//DD		= case (cs_main_library_instance_i) == library_instance_i of {
		= case ((n_library_instances - RTID_LIBRARY_INSTANCE_ID_START)  < 2) of {
			True
				-> (dl_client_state,io);
			False
//DD...
//				| isNothing xx
//					-> abort ("LoadLibraryInstanceTypeTable: no main library instance chosen yet" +++ toString library_instance_i);
				#! cs_main_library_instance_i
					= RTID_LIBRARY_INSTANCE_ID_START; //fromJust xx;
// ... DD


//				| True
//					-> abort "tweede library"
				// all other dynamics must communicate with the application, so they all need to agree on 
				// at least a single representation for Dynamics and the types of dynamics. There is only
				// one choice, taking the implementation of the application because it is loaded and linked
				// first.
				# dynamicje
					= { 
						tr_type_name	= DynamicRepresentation_String
					,	tr_module_name1	= UnderscoreSystemDynamicModule_String
					,	tr_module_name2	= UnderscoreSystemDynamicModule_String
					,	tr_library2		= Number cs_main_library_instance_i 	// will be 2nd arg of enter_type_equation
					,	tr_library1		= Number library_instance_i				// RunTimeID (not diskID)
					};
					
				// graph_to_string-instances must share a single LazyDynamicReference
				# lazy_dynamic_reference
					= { 
						tr_type_name	= LazyDynamicReference_String
					,	tr_module_name1	= StdDynamicLowLevelInterfaceModule_String
					,	tr_module_name2	= StdDynamicLowLevelInterfaceModule_String
					,	tr_library2		= Number cs_main_library_instance_i 	// will be 2nd arg of enter_type_equation
					,	tr_library1		= Number library_instance_i				// RunTimeID (not diskID)
					};

				# global_dynamic_info_dummy
					= { 
						tr_type_name	= GlobalDynamicInfoDummy_String
					,	tr_module_name1	= UnderscoreSystemDynamicModule_String
					,	tr_module_name2	= UnderscoreSystemDynamicModule_String
					,	tr_library2		= Number cs_main_library_instance_i 	// will be 2nd arg of enter_type_equation
					,	tr_library1		= Number library_instance_i				// RunTimeID (not diskID)
					};
					
				// The predefined types defined in the run-time system are shared among all library instances because it
				// is/will be used by all library instances, if necessary.
/*
				# realtje
					= { 
						tr_type_name	= "Real"
					,	tr_module_name1	= PredefinedModuleName
					,	tr_module_name2	= PredefinedModuleName
					,	tr_library2		= Number cs_main_library_instance_i 	// will be 2nd arg of enter_type_equation
					,	tr_library1		= Number library_instance_i				// RunTimeID (not diskID)
					};
*/
					
				// main library instance provides the implementation
				#! (ok,dl_client_state,io)
					= CheckAndEnterType [dynamicje/*,realtje*/,lazy_dynamic_reference,global_dynamic_info_dummy] (Just cs_main_library_instance_i) dl_client_state io;
				| not ok
					-> abort "internal/external error; representation of dynamics has changed";

					
					// DLClientState
				#! (cs_n_fixed_available_types,dl_client_state)
					= dl_client_state!cs_n_fixed_available_types;
				#! (dl_client_state,io)
					= case cs_n_fixed_available_types of {
						Nothing
							// it is assumed that a type equivalent class which already has an implementation i.e.
							// the type implementation has been linked, is marked as such in the available array
							// below.
							#! (teit_n_type_implementations,dl_client_state)
								= dl_client_state!cs_type_implementation_table.teit_n_type_implementations;
							#! li_type_available
								= createArray teit_n_type_implementations True;
							#! dl_client_state
								= { dl_client_state & 
									cs_library_instances.lis_library_instances.[cs_main_library_instance_i].li_s_type_available = teit_n_type_implementations
								,	cs_library_instances.lis_library_instances.[cs_main_library_instance_i].li_type_available = li_type_available
								};
							#! dl_client_state
								= { dl_client_state &
									cs_n_fixed_available_types	= Just teit_n_type_implementations };

/*
// /* NEW2
							// a type implementation for a particular type equivalent class has been implemented if
							// *all* of the labels implementing the type have been linked.
							#! (labels_to_be_linked,dl_client_state)
								= loopAst link_label ([],dl_client_state) teit_n_type_implementations;
//								= loop_on_types cs_main_library_instance_i dl_client_state;
							#! (dl_client_state,io)
								= LoadLibraryInstance_new cs_main_library_instance_i (Just labels_to_be_linked) dl_client_state io;
								
// */
*/
							#! dl_client_state
								= print_type_implementation_table dl_client_state;

							-> (dl_client_state,io);
						Just _
							-> (dl_client_state,io);
					
					};
					
				// internal types moeten ook nog and basic types
				-> (dl_client_state,io);
		};
	= (dl_client_state,io);
where {
	// communication is done by dynamics. So the DynamicTemp and its type (and further types it depends upon)
	// must at the very least be constructible e.i. there exists a correctly typed Clean graph. The value may
	// not be (this depends on the type which describes the value). Here it is ensure that *all* labels which
	// implement the DynamicTemp-type are linked in.
	// Furthermore predefined types e.g. ints, reals, lists, etc. are also shared by all library instances.
/*
	link_label_obsolete type_implementation_ref (labels,dl_client_state)
		#! (Just type_ref,dl_client_state)
			= getImplementationType type_implementation_ref dl_client_state;
		#! (library_instance_i,tio_type_reference)
			= get_non_predefined_type type_ref;
		#! cs_main_library_instance_i
			= fromJust cs_main_library_instance_i;
		| library_instance_i <> cs_main_library_instance_i
			= abort ("link_label: internal error; main library instance must implement type");

		#! (li_type_table_i,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
		#! (type_name,labels_implementing_type,dl_client_state)
			= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
			
		#! labels_implementing_type
			= [ {default_elem & 
					dusl_label_name = label_name
				,	dusl_library_instance_i = cs_main_library_instance_i
				,	dusl_label_kind			= DSL_TYPE_EQUIVALENT_CLASS_IMPLEMENTATION
				} \\ label_name <- labels_implementing_type ];

		= (labels_implementing_type ++ labels,dl_client_state);
	where {
		get_non_predefined_type (LIT_TypeReference library_instance_i tio_type_ref) //=:{tio_type_without_definition=Nothing})
			= (library_instance_i,tio_type_ref);

	} // link_label
	
*/
}

/*
loop_on_types library_instance_i dl_client_state=:{cs_main_library_instance_i}	
	// general
	#! (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (tt_n_tio_common_defs,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_n_tio_common_defs;

	#! (labels,dl_client_state)
		= loopAst (loop_on_module type_table_i) ([],dl_client_state) tt_n_tio_common_defs;

	= (labels,dl_client_state);
where {
	loop_on_module type_table_i tio_tr_module_n (labels,dl_client_state)
		// loop on type definitions
		# (tio_com_type_defs,dl_client_state)
			= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs;
		# (labels,dl_client_state)
			= mapAiSt loop_on_type_def tio_com_type_defs (labels,dl_client_state);
		= (labels,dl_client_state);
	where {
		loop_on_type_def tio_tr_type_def_n {tio_td_name} (labels,dl_client_state)
			# tio_type_reference
				= { default_elem &
					tio_tr_module_n		= tio_tr_module_n
				,	tio_tr_type_def_n	= tio_tr_type_def_n
				};
			# (maybe_any_constructor_of_type_implemented,dl_client_state)
				= isAnyConstructorOfTypeImplemented (LIT_TypeReference library_instance_i tio_type_reference) dl_client_state;
			| isNothing maybe_any_constructor_of_type_implemented
				// type unused in this library instance
				= (labels,dl_client_state);


// huidige library instance bevat al een gedeeltelijk implementation van het type				
			# (type_name,labels_implementing_type)
				= fromJust maybe_any_constructor_of_type_implemented;
				
			# (unimplemented_label_names,dl_client_state)	
				= foldSt add_unlinked_label labels_implementing_type (labels,dl_client_state);
			= (unimplemented_label_names,dl_client_state);
		where {
			add_unlinked_label label_name (labels,dl_client_state)
				# (is_linked_label_name,dl_client_state)
					= check_whether_implementation_is_available library_instance_i label_name dl_client_state;
				| is_linked_label_name
					= (labels,dl_client_state);
					
					#! dl_client_state
						= dl_client_state <<- ("add_unlinked_label: ",label_name)
						
					#! label_implementing_type
						= {default_elem & 
								dusl_label_name 		= label_name
							,	dusl_library_instance_i = library_instance_i
							,	dusl_label_kind			= DSL_TYPE_EQUIVALENT_CLASS_IMPLEMENTATION
						};
					= ([label_implementing_type:labels],dl_client_state);
		} // loop_on_type_def
	}
};

*/


/*
check_whether_implementation_is_available :: !Int !String !*DLClientState -> (!Bool,!*DLClientState);
check_whether_implementation_is_available library_instance_i label_name dl_client_state
	#! (li_library_initialized,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized;
	| not li_library_initialized
		= (False,dl_client_state);
	
	#! (Just (file_n,symbol_n),dl_client_state)
		= findLabel label_name library_instance_i dl_client_state;
	#! (maybe_address,dl_client_state)
		= isLabelImplemented file_n symbol_n dl_client_state;
	= (isJust maybe_address,dl_client_state);

isTypeImplemented :: !LibraryInstanceTypeReference !*DLClientState -> (!Maybe !(!String,[String]),*DLClientState);
isTypeImplemented (LIT_TypeReference library_instance_i tio_type_reference=:{tio_type_without_definition=Nothing}) dl_client_state
	#! (li_type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (type_name,labels_implementing_type,dl_client_state)
		= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
	#! (implementation_is_available,dl_client_state)
		= anySt (check_whether_implementation_is_available library_instance_i) labels_implementing_type dl_client_state;
//	#! (any_implementation_is_available,dl_client_state)
//		= anySt check_whether_implementation_is_available labels_implementing_type dl_client_state;
	| implementation_is_available // <<- ("isTypeImplemented", implementation_is_available, "any=", any_implementation_is_available, library_instance_i, labels_implementing_type)
		= (Just (type_name,labels_implementing_type),dl_client_state);
		= (Nothing,dl_client_state);

*/
	// collect 
		
/* DLClientState
	AddTypeTable type_table_index type_table=:{tt_n_tio_common_defs,tt_type_io_state={tis_string_table}} a
//		| True <<- "AddTypeTable"
		// NEW ...	
		# hash_table
			= { [] \\ i <- [0 .. dec cHashTableSize] }; 
		# (hash_table,type_table)
			= loopAst loop_on_module (hash_table,type_table) tt_n_tio_common_defs;

*/
		
		// DLClientState


LoadTypeTable :: .Int *DLClientState *a -> *(*DLClientState,*a) | FileEnv a;
LoadTypeTable type_table_i dl_client_state io
//	| True <<- ("LoadTypeTable",type_table_i)
	
	# (tt_loaded,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_loaded;
	| tt_loaded
		= (dl_client_state,io);

		// load type table
		# (tt_name,dl_client_state)
			= dl_client_state!cs_type_tables.[type_table_i].tt_name;
		# ((ok,rti,tio_common_defs,type_io_state,_),io)
			= accFiles (read_type_library_new False tt_name) io;
		| not ok
			#! msg
				= "Loaded type table " +++ toString type_table_i +++ ": " +++ tt_name;
			#! dl_client_state
				= AddMessage (LinkerError msg) dl_client_state;
			= (dl_client_state,io);
	
		// create new type table
		# new_type_table
			= { default_type_table &
				tt_type_io_state		= type_io_state
			,	tt_tio_common_defs		= { x \\ x <-: tio_common_defs }
			,	tt_n_tio_common_defs	= size tio_common_defs
			,	tt_rti					= rti
			};
		# dl_client_state
			= AddTypeTable type_table_i new_type_table dl_client_state;
			
		// print that type library has been loaded
		#! dl_client_state
			= AddMessage (Verbose ("Loaded type table " +++ toString type_table_i +++ ": " +++ tt_name)) dl_client_state;
		
		= (dl_client_state,io);

// Loads an application from a library
// 
// Output:
// - for each set of type equivalence with at least two types, a single implementation has been linked in.
LoadApplication :: !ProcessSerialNumber [String] !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!ProcessSerialNumber,!*DLServerState, !(IOState !*DLServerState));
LoadApplication client_id _ s io
	// copy from Init
	#! (client_exists,dl_client_state,s)
		= RemoveFromDLServerState client_id s;
	| not client_exists
		= internal_error "LoadApplication (internal error): client not registered" client_id dl_client_state s io;
		
	# (main_code_type_lib,dl_client_state)
		= dl_client_state!cs_main_library_name;
	#! dl_client_state
		= AddMessage (Verbose ("LoadApplication: " +++ main_code_type_lib)) dl_client_state;
		
	#! args
		= [];
		
	// check args-argument of Init-request
	#! dl_client_state
		= case (sel_platform True False) of {
			True
				// winOS
				| not (isEmpty args) 
					#! dl_client_state
						= AddMessage (LinkerError "args argument of Init in Request.icl cannot have arguments") dl_client_state;
					-> dl_client_state;
					-> dl_client_state;
			False
				// macOS
 /*
				| length args <> 1 //isEmpty args
					#! dl_client_state
						= AddMessage (LinkerError "args argument of Init in Request.icl should have exactly one parameter") dl_client_state;
					-> dl_client_state;
					
					#! dl_client_state
						= app_pd_state (\pd_state -> {pd_state & qd_address = FromStringToInt (hd args) 0}) dl_client_state;
					-> dl_client_state;
 */
 				-> abort "LoadApplication; Init (line 131) uncomment!!!";

		}
		
	#! (dlink_dir,s)
		= GetDynamicLinkerDirectory s;
	#! (to_and_from_graph_table,io)
		= init_to_and_from_graph_table dlink_dir io;

		
		
		
	#! (library_instance_i,_,dl_client_state=:{cs_main_library_instance_i},io)
		= RegisterLibrary Nothing True main_code_type_lib dl_client_state io;
//	| isJust cs_main_library_instance_i
//		= abort "LoadApplication; internal error application can only be loaded once";
	# dl_client_state
		= { dl_client_state & 
//DD			cs_main_library_instance_i = Just library_instance_i ,
			cs_to_and_from_graph	= to_and_from_graph_table
		};
		
	#! (state,dl_client_state)
		= get_state dl_client_state;
	#! dl_server_state
		= s;
	#! (start_addr,_,state,dl_client_state/*,dl_server_state*/,io)
//		= LoadCodeLibraryInstance state { dl_client_state & lib_link = True } s io; 
		= LoadLibraryInstance library_instance_i Nothing state { dl_client_state & lib_link = True } /* s*/ io; 


//	#! (start_addr,state,dl_client_state,dl_server_state,io)
//		= LoadLib state { dl_client_state & lib_link = True } s io; 

	# io
		= SendAddressToClient client_id (FromIntToString start_addr) io;
		
	# dl_client_state
		 = { dl_client_state &
		 		app_linker_state	= state
		 };
		 
// new...
/* NEW2

	// ensure that all the prefixes of constructors have been loaded.
	#! (cs_main_library_instance_i,dl_client_state)
		= dl_client_state!cs_main_library_instance_i;
	#! cs_main_library_instance_i
		= fromJust cs_main_library_instance_i;
	#! (labels_to_be_linked,dl_client_state)
		= loop_on_types cs_main_library_instance_i dl_client_state;
	#! dl_client_state
		= dl_client_state <<- ("Test", map (\r=:{dusl_label_name} -> {r & dusl_label_name = "\n" +++ dusl_label_name}) labels_to_be_linked);
	#! (dl_client_state,io)
		= LoadLibraryInstance_new cs_main_library_instance_i (Just labels_to_be_linked) dl_client_state io;
*/
// ...new

	# dl_client_state
		= AddMessage (Verbose ("###start:" +++ (hex_int start_addr))) dl_client_state;
		
	// check for errors
	#! (ok,dl_client_state)
		= IsErrorOccured {dl_client_state & initial_link = False};
		
//	| F (hex_int start_addr) True
	
	= (not ok,client_id,AddToDLServerState dl_client_state dl_server_state,/*KillClient3 client_id ok*/ io);
where {
	get_state dl_client_state=:{app_linker_state}
		= (app_linker_state,{dl_client_state & app_linker_state = EmptyState});
}

//LoadLibraryInstance :: !.Int !.Bool !*State !*DLClientState !*DLServerState *(IOState *DLServerState) -> *(Int,*State,*DLClientState,*DLServerState,*IOState *DLServerState);



LoadLibraryInstance library_instance_i non_main_library state dl_client_state=:{lib_link,cs_main_library_instance_i} /*dl_server_state*/ io
	| /*isJust non_main_library ||*/ not lib_link
		= abort "LoadLibraryInstance: not as_application or not lib_link unimplemented";

	# (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	# (dl_client_state,io)
//		= LoadTypeTable type_table_i dl_client_state io;
		= LoadLibraryInstanceTypeTable library_instance_i type_table_i dl_client_state io
		
//	CheckAndEnterType :: [.TypeReference] *DLClientState *(IOState DLServerState) -> *(Bool,*DLClientState,*IOState DLServerState);

// DLClientState
	= LoadCodeLibraryInstance non_main_library library_instance_i type_table_i state dl_client_state /*dl_server_state*/ io;

//RegisterLibrary :: !String !*s -> *(!Int,!Int,!*s) | AddMessage, Library_Instances, TypeTableOps s;	
RegisterLibrary dynamic_index is_main_library library_name s io
	# (type_table_i,s)
		= AddReferenceToTypeTable library_name s;
	// ensure type table is alwas loaded; in future should be lazily done
//	# (s,io)
//		= LoadTypeTable type_table_i s io;

		
	# (library_instance_i,s)
		= AddLibraryInstance dynamic_index library_name type_table_i s;
		
	// print		
	#! msg
		= "Register library as library instance #" +++ toString library_instance_i +++ " and name '" +++ library_name +++ "'";
	#! (s)
		= AddMessage (Verbose msg) s;

//DD	# s
//DD		= case is_main_library of {
//DD			True	-> { s & cs_main_library_instance_i = Just library_instance_i };
//DD			False	-> s;
//DD		};

		
	# (s,io)
		= LoadLibraryInstanceTypeTable library_instance_i type_table_i s io;
		

	= (library_instance_i,type_table_i,s,io);

from SearchObject import add_module2, add_library2;

// loads both the code library assumes type table has already been loaded. The redirections to be made are derived from the 
// type table and imposed on the code.
LoadCodeLibraryInstance :: (Maybe [.DusLabel]) !.Int !Int !*State !*DLClientState !(IOState !*DLServerState) -> (!Int,[Int],!*State,!*DLClientState /*,!*DLServerState*/ ,!(IOState !*DLServerState));
LoadCodeLibraryInstance non_main_library library_instance_i type_table_i state dl_client_state=:{lib_link} /* dl_server_state */ io
	| not lib_link
		= abort "LoadLib: you need the library approach to dynamics";
		
	# (li_library_name,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_name;
	# li_library_name
		= fromJust li_library_name;

	// get names table
	#! (li_library_initialized,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized;
	#! (share_runtime_system,state,dl_client_state,io)
		= case li_library_initialized of {
			True
/*
				#! (cs_main_library_instance_i,dl_client_state)
					= dl_client_state!cs_main_library_instance_i;
				| ((fromJust cs_main_library_instance_i) <> library_instance_i) <<- non_main_library
					// the memory areas occupied by the main library instance can increase in size. The
					// memory areas of other library instances cannot because they have completely been
					// linked. The main library instance can only be extended with conversion functions.
					// False!!
					-> abort ("only the main library instance may expand its memory usage" +++ toString library_instance_i);
*/

				// library list zetten in state
				#! (li_library_list,dl_client_state)
					= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_list;
				#! (names_table,dl_client_state)
					= acc_names_table library_instance_i dl_client_state;
				#! state = { state & 
						namestable				= names_table
					,	library_list 			= li_library_list
					};
				-> (False,state,dl_client_state,io);				
			False
				// DumpDynamic ...
				#! (Just main_library_instance_i,dl_client_state)
					= dl_client_state!cs_main_library_instance_i;
				#! (do_dump_dynamic,dl_client_state)
					= dl_client_state!do_dump_dynamic;
				#! is_dump_dynamic_main_library
					= library_instance_i == main_library_instance_i && do_dump_dynamic;
					
				#! is_main_library_instance
					= library_instance_i == main_library_instance_i;
					
//				| True <<- ("conditie",do_dump_dynamic && library_instance_i <> main_library_instance_i,library_instance_i,main_library_instance_i)
//				#! share_runtime_system
//					=  (isJust non_main_library && (not do_dump_dynamic))
//					|| (do_dump_dynamic && library_instance_i <> main_library_instance_i);

				#! (share_runtime_system,dl_client_state)
					= dl_client_state!cs_share_runtime_system;
				#! dl_client_state
					= { dl_client_state & cs_share_runtime_system = True };
				# dl_client_state
					= case share_runtime_system of {
						False
							-> { dl_client_state &
								cs_main_library_instance_i = Just library_instance_i
								};
						_
							-> dl_client_state;
					};

//				| True 
//					-> abort (toString library_instance_i);
				// DLClientState
				// ... DumpDynamic
				
				// DLClientState
					 
				// load library
				# ({rti_n_libraries=n_libraries,rti_n_library_symbols=n_library_symbols,rti_library_list=library_list},dl_client_state)
					= dl_client_state!cs_type_tables.[type_table_i].tt_rti;


				// mark library instance i as initialized
				#! dl_client_state 
					= { dl_client_state &
						cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized = True
					};
					
					
				#! (n_old_libraries,state)
					= state!n_libraries;
					
				
				// import DLL symbols
				#! (symbol_n,library_n,names_table)
					= ImportDynamicLibrarySymbols library_list 0 (~(n_libraries + n_old_libraries)) create_names_table;
				| symbol_n <> n_library_symbols || library_n <> (~n_old_libraries)
					-> abort "LoadCodeLibraryInstance: internal error; .typ-file corrupt";
					// LibraryList
				#! state
					= case non_main_library of {
						_	-> add_library2 n_libraries n_library_symbols library_list state;
						_	-> state;
					};

				// load code library *without* run-time system which is shared with the main library
				// instance.
				# (do_dump_dynamic,dl_client_state)
					= dl_client_state!do_dump_dynamic;

				# (rs,dl_client_state)
					= case share_runtime_system of { // non_main_library of { //is_main_library_instance of { //(isNothing non_main_library) && (is_dump_dynamic_main_library of {
						False //Nothing //False //True //Nothing 
							-> (default_redirection_state,dl_client_state);
						_
						//(Just main_library_instance_i)
							# (cs_main_library_instance_i,dl_client_state)
								= dl_client_state!cs_main_library_instance_i;
							# main_library_instance_i
								= fromJust cs_main_library_instance_i;

							# library_name
								= (snd (ExtractPathAndFile li_library_name));
							# library_name
								= "_" +++ (library_name % (0,size library_name - 2))   +++ "_options.o";
							# rts_objects
								= ["_startup0.o",library_name,"_startup1.o","_startup2.o","_startup1Profile.o","_startup1Trace.o","_system.o"];
							#! (names_table,dl_client_state)
								= acc_names_table main_library_instance_i dl_client_state;					

							# rs
								= { default_redirection_state &
								 	rs_main_names_table		= names_table
								,	rs_rts_modules			= rts_objects
								};
//							| True <<- "klaar"
							-> (rs,dl_client_state);
					};
					
				# (n_xcoff_files,state)
					= state!n_xcoff_files;
				# code_lib_name
					= build_code_lib_name li_library_name;
				# (s_names_table,names_table)
					= usize names_table;
				# names_table 
					= names_table <<- ("in!","s_names_table:",s_names_table)
				# ((errors, xcoff_l, names_table, _,rs),io)
					= accFiles (read_code_library2 (n_xcoff_files) [] code_lib_name names_table rs) io;				
				# names_table 
					= names_table <<- ("out","s_names_table:",s_names_table)

				// restore name table
				# dl_client_state
					= case share_runtime_system of { // non_main_library of { //is_main_library_instance of { //(isNothing non_main_library) || do_dump_dynamic of { //non_main_library of {
						False //Nothing //False //True //Nothing 
							-> dl_client_state;
						_ // False // Just _
							# (cs_main_library_instance_i,dl_client_state)
								= dl_client_state!cs_main_library_instance_i;
							# main_library_instance_i
								= fromJust cs_main_library_instance_i;

							# dl_client_state
								= { dl_client_state &
									cs_library_instances.lis_library_instances.[main_library_instance_i].li_names_table = rs.rs_main_names_table 
								};
							-> dl_client_state;
					};

/*
				// resolve symbolic references by name
				# (undefined_symbols,xcoff_l,names_table)
					= import_symbols_in_xcoff_files xcoff_l n_xcoff_files [] names_table;		
				| not (isEmpty undefined_symbols) <<- undefined_symbols
					-> abort ("LoadLib: internal error undefined_symbols should be empty" +++ (fst3 (hd undefined_symbols)));
*/
					
				#! state = { state & 
					namestable				= names_table
				,	library_list 			= library_list
				};

					
				// add_module
				#! state
					= foldSt add_module2 xcoff_l state;
					
				// ------------------------
				// A lazy dynamic is marked by a BUILD_BLOCK_LABEL or a BUILD_LAZY_BLOCK_LABEL. Each library also defines these
				// two labels. Without precautions, these copies would also be put in the image, making the conversion routines
				// much more complex. Therefore the copy of the main library instance is taken and references of other library
				// instance are redirected to those of the main library instance.
				
				// backup namestable from state
				#! (names_table,state)
					= select_namestable state;
				#! dl_client_state
					= { dl_client_state &
						cs_library_instances.lis_library_instances.[library_instance_i].li_names_table = names_table
					};
					
				// body ...
				#! (state,dl_client_state)
					= case share_runtime_system of {
						False
							-> (state,dl_client_state);
						True
							// backup state
							#! dl_client_state
								= { dl_client_state &
									app_linker_state = state
								};
								
							// replace BUILD_BLOCK_LABEL
							#! (Just main_library_instance_i,dl_client_state)
								= dl_client_state!cs_main_library_instance_i;
							#! (Just (build_block_file_n,build_block_symbol_n),dl_client_state)
								= findLabel BUILD_BLOCK_LABEL main_library_instance_i dl_client_state;
							#! dl_client_state
								= replaceLabel BUILD_BLOCK_LABEL library_instance_i build_block_file_n build_block_symbol_n BUILD_BLOCK_LABEL dl_client_state;

							// replace BUILD_LAZY_BLOCK_LABEL
							#! (Just (build_lazy_block_file_n,build_lazy_block_symbol_n),dl_client_state)
								= findLabel BUILD_LAZY_BLOCK_LABEL main_library_instance_i dl_client_state;
							#! dl_client_state
								= replaceLabel BUILD_LAZY_BLOCK_LABEL library_instance_i build_lazy_block_file_n build_lazy_block_symbol_n BUILD_LAZY_BLOCK_LABEL dl_client_state;
								
							// extract state
							#! (state,dl_client_state)
								= acc_state (\state -> (state,EmptyState)) dl_client_state;
							
							-> (state,dl_client_state);
					};
				// ... body
					

				// restore namestable in state
				#! (names_table,dl_client_state)
					= acc_names_table library_instance_i dl_client_state;
				#! state = { state & 
						namestable				= names_table
					};
				// ------------------------
				-> (share_runtime_system,state,dl_client_state,io);
		};
		
// latest...
	#! (names_table,state)
		= select_namestable state;
	#! (library_list,state)
		= state!library_list
	#! dl_client_state
		= { dl_client_state &
			cs_library_instances.lis_library_instances.[library_instance_i].li_names_table = names_table
		,	app_linker_state	= state
		};
		
	// DLClientState

/*
	#! (dl_client_state,dl_server_state,io)
		= update_namestable_to_include_recent_type_implementations library_instance_i dl_client_state dl_server_state io;
*/
	#! (dl_client_state,io)
		= update_namestable_to_include_recent_type_implementations library_instance_i dl_client_state io;
		
	#! (names_table,dl_client_state)
		= acc_names_table library_instance_i dl_client_state;
	#! (state,dl_client_state)
		= acc_state (\s -> (s,EmptyState)) dl_client_state;
	#! state 
		= { state &
			namestable = names_table
		,	library_list = library_list
		};

// ... latest

	#! (main_symbols,dl_client_state)
		= case non_main_library of {
			Nothing
				#! main_symbol
					= sel_platform "_mainCRTStartup" "main";
				#! main_symbols
					= [		SymbolUnknown  "" main_symbol
//						,	SymbolUnknown "" "e____SystemDynamic__kRunTimeID"	// temp solution
						
						,	SymbolUnknown "" BUILD_BLOCK_LABEL
						,	SymbolUnknown "" BUILD_LAZY_BLOCK_LABEL
						];
						
				#! (teit_n_type_implementations,dl_client_state)
					= dl_client_state!cs_type_implementation_table.teit_n_type_implementations;
				-> (main_symbols,dl_client_state);
			(Just dus_labels)
				// exclude label which already have been linked by other library instances
				#! labels
					= [ SymbolUnknown "" dusl_label_name \\ {dusl_label_name,dusl_linked} <- dus_labels | not dusl_linked];
				-> (labels,dl_client_state);
		};

	/*
	** The preliminary temp solution above ensures that the RunTimeID-constructor is allocated into
	** library space and not lazily allocated in space for the graph_to_string-conversion function
	** which is not a library instance and therefore not included in the table which is sent to the
	** application and contains start/end addresses for each library instance. 
	** In the future the RunTimeID constructor of the context library should be used.
	*/ 
	#! ((wii,p=:[start_addr:_],state,dl_client_state),io)
		= LinkUnknownSymbols main_symbols state library_instance_i dl_client_state io;
	
	| True <<- ("wii",wii)
//	#! c_p
//		= foldSt (+) p 0;
//	| True <<- ("",c_p)


		
		// LibraryList
		
	#! (library_list,names_table,state)
		= case (USE_OLD_NAMESTABLE_STORAGE True False) of {
			True
				-> (EmptyLibraryList,create_names_table,state);
			False
				#! (names_table,state)
					= select_namestable state;
				#! (library_list,state)
					= state!library_list;
				-> (library_list,names_table,state);
		};
	// will become obsolete
	#! dl_client_state
		= case wii of {
			Nothing
				-> dl_client_state;
			Just {wii_code_start,wii_code_end,wii_data_start,wii_data_end}
				#! (li_memory_areas,dl_client_state)
					= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas;
				#! li_memory_areas
					= [{ma_begin=wii_data_start,ma_end=wii_data_end},{ma_begin=wii_code_start,ma_end=wii_code_end}:li_memory_areas];
				#! dl_client_state
					= { dl_client_state &
						cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas = li_memory_areas
					};
				-> dl_client_state;
		};
		
/*
	# ms
		= { default_memory_state &
		// Library name
			ms_library_name			= li_library_name
		,	ms_type_table_index		= Just type_table_i
			
		// run-time memory areas
		,	ms_code_begin			= wii.wii_code_start
		,	ms_code_end				= wii.wii_code_end
		,	ms_data_begin			= wii.wii_data_start
		,	ms_data_end				= wii.wii_data_end
		};
	*/

	// update		
	#! dl_client_state 
		= {  dl_client_state &
			cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized = True
		,	cs_library_instances.lis_library_instances.[library_instance_i].li_library_list = library_list
		,	cs_library_instances.lis_library_instances.[library_instance_i].li_names_table = names_table
/*
		,	cs_library_instances.lis_library_instances.[library_instance_i].li_code_begin = wii.wii_code_start
		,	cs_library_instances.lis_library_instances.[library_instance_i].li_code_end	=  wii.wii_code_end
		,	cs_library_instances.lis_library_instances.[library_instance_i].li_data_begin = wii.wii_data_start
		,	cs_library_instances.lis_library_instances.[library_instance_i].li_data_end = wii.wii_data_end
	*/

//		,	cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas = [undef] 
//		++ dl_client_state.cs_library_instances.lis_library_instances.[library_instance_i].li_memory_areas

		} // <<- ("code",wii.wii_code_start,wii.wii_code_end);
		
		// DLClientState
/*
	# dl_client_state
		= { dl_client_state &
			cs_memory_state			=[ms:dl_client_state.cs_memory_state]
		};
*/

//						,	SymbolUnknown "" ""
//						,	SymbolUnknown "" ""

//	#! 
//		= findLabel "e____SystemDynamic__nbuild__block" library_instance dl_client_state
// findLabel :: !String !Int !*DLClientState -> (!Maybe !(!Int,!Int),!*DLClientState);


/*
	#! (state,dl_client_state)
		= case share_runtime_system of {
			True
				-> (state,dl_client_state);
			False
				#! dl_client_state
					= { dl_client_state &
						app_linker_state = state
					};
					
				// replace BUILD_BLOCK_LABEL
				#! (Just main_library_instance_i,dl_client_state)
					= dl_client_state!cs_main_library_instance_i;
				#! (Just (build_block_file_n,build_block_symbol_n),dl_client_state)
					= findLabel BUILD_BLOCK_LABEL main_library_instance_i dl_client_state;
				#!
					= replaceLabel BUILD_BLOCK_LABEL library_instance_i 
					
					
	




					
					// DLClientState
					
					
					
					
					
					
				#! (symbolQ=:(Module _ _ _ _ _ _),state) 
					= state!xcoff_a.[build_block_file_n].symbol_table.symbols.[build_block_symbol_n];
					
					// Module
				| True <<- ("ok",symbolQ,"\n",state)	
				-> abort "jaa";
		};
*/				
	= (start_addr,p,state,dl_client_state /*,dl_server_state*/ ,io);

where {
	check_label dl_client_state=:{cs_main_library_instance_i=Just main_library_instance_i}
		#! (Just (file_n,symbol_n),dl_client_state)
			= findLabel BUILD_BLOCK_LABEL main_library_instance_i dl_client_state
			
			
		= dl_client_state;	
	where {
		check_a_label label dl_client_state
			= undef
			
	
	}
	


//		#!
//			= findLabel BUILD_BLOCK_LABEL 





	f :: !*DLClientState -> !*DLClientState;
	f i = i;
/*
	copy_array i limit old_array new_array 
		| i == limit
			= new_array;

			# (elem,old_array)
				= replace old_array i default_type_table;	
			= copy_array (inc i) limit old_array {new_array & [i] = elem};

*/

read_code_library2 file_n module_to_be_removed code_lib_name names_table rs files 
	# (errors, xcoff_l, _, names_table, file_n, files,_,rs)
		= read_static_lib_files_new module_to_be_removed [code_lib_name] [] names_table file_n [] files default_rsl_state rs;
	= ((errors, xcoff_l, names_table, file_n,rs), files);

/*	
	read_type_library :: !String *Files -> *(*(Bool,RTI,.{#TIO_CommonDefs},*TypeIOState,*{!NamesTableElement}),*Files);	
	read_type_library ls_main_code_type_lib files
		# (ok,rti,tio_common_defs,type_io_state,names_table,files)
			= read_type_information (build_type_lib_name ls_main_code_type_lib) create_names_table files;
		= ((ok,rti,tio_common_defs,type_io_state,names_table),files)
*/
};








// SHOULD BE MORE SPECIALIZED TO ENFORCE MORE EFFICIENT CODE
instance findTypeUsingTypeName DLClientState
where {
	findTypeUsingTypeName type_name module_name type_table_i dl_client_state
		# (type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# (result,type_tables)
			= findTypeUsingTypeName type_name module_name type_table_i type_tables;
		# dl_client_state 
			= { dl_client_state &
				cs_type_tables	= type_tables
			};
		= (result,dl_client_state);
};

instance findTypeUsingConstructorName DLClientState
where {
	findTypeUsingConstructorName type_name module_name type_table_i dl_client_state
		# (type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# (result,type_tables)
			= findTypeUsingConstructorName type_name module_name type_table_i type_tables;
		# dl_client_state 
			= { dl_client_state &
				cs_type_tables	= type_tables
			};
		= (result,dl_client_state);
};

instance findModuleName DLClientState
where {
	findModuleName module_name type_table_i dl_client_state
		# (type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# (result,type_tables)
			= findModuleName module_name type_table_i type_tables;
		# dl_client_state 
			= { dl_client_state &
				cs_type_tables	= type_tables
			};
		= (result,dl_client_state);
};

/*
instance findImplementationType DLClientState
where {
	findImplementationType litr dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# (is_type_equation,type_implementation_ref,type_implementation_table)
			= findImplementationType litr type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= (is_type_equation,type_implementation_ref,dl_client_state);
};

*/

/*

			# (type_implementation_table,dl_client_state)
					= get_type_implementation_table dl_client_state;
				# (type_tables,dl_client_state)
					= get_type_tables dl_client_state;
			
				// pass 2: generate type equations
				# (type_implementation_table,type_tables,dl_client_state)
					= foldSt generate_type_equations equivalent_type_defs (type_implementation_table,type_tables,dl_client_state);

				// update dl_client_state
				# dl_client_state
					= { dl_client_state &
						cs_type_tables					= type_tables
					,	cs_type_implementation_table	= type_implementation_table

*/

instance getImplementationType DLClientState
where {
	getImplementationType index_of_type_equivalence_class dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# (implementation_type,type_implementation_table)
			= getImplementationType index_of_type_equivalence_class type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= (implementation_type,dl_client_state);
};

instance enter_implementation_type_for_equivalence_class2 DLClientState
where {
	enter_implementation_type_for_equivalence_class2 index_of_type_equivalence_class type_implementing_type_equivalence_class dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# type_implementation_table
			= enter_implementation_type_for_equivalence_class2 index_of_type_equivalence_class type_implementing_type_equivalence_class type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= dl_client_state;
};

instance enter_implementation_type_for_equivalence_class DLClientState
where {
	enter_implementation_type_for_equivalence_class index_of_type_equivalence_class library_instance_i_implements_type_equivalence_class dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# type_implementation_table
			= enter_implementation_type_for_equivalence_class index_of_type_equivalence_class library_instance_i_implements_type_equivalence_class type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= dl_client_state;
};
		/*
		# (type1_has_been_implemented,dl_client_state)
			= has_type_an_implementation type1 dl_client_state;
		# dl_client_state
			= case created_new_type_equivalence_class of {
				True
					# (type2_has_been_implemented,dl_client_state)
						= has_type_an_implementation type2 dl_client_state;
					| type1_has_been_implemented && (not type2_has_been_implemented)
						// type1 is implementation type for that class
						-> enter_implementation_type_for_equivalence_class2 index_of_type_equivalence_class type1 dl_client_state;
					| type2_has_been_implemented && (not type1_has_been_implemented)
						-> abort "type2";
					| type2_has_been_implemented && type1_has_been_implemented
						-> abort "none";
						
						-> abort "stop";
				False
					// alleen type1 controleren omdat type2 geldt als representant van de type equivalentie klasse.
					// Voor een type equivalentie klasse zonder implementatie type geldt buiten het linken altijd
					// dat geen van de mogelijke type implementaties uit de equivalentie klasse een daadwerkelijke
					// implementatie heeft.
					-> abort "klsfdklklklkl";
			};
		// ...body
		*/

instance enter_type_equation DLClientState
where {
	enter_type_equation type1 type2 dl_client_state
		| isTypeWithoutDefinition type1 && isTypeWithoutDefinition type2
			= (Nothing,dl_client_state); //abort "types without definitions are implemented in the rts and are shared by default";
			
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
			
		// body...
		
		// pattern below only fails when type equation without definition (in a icl-module) have been entered
		// in the type implementation table. The type implementation table is then invalid.
		# (Just (index_of_type_equivalence_class,created_new_type_equivalence_class),type_implementation_table)
			= enter_type_equation type1 type2 type_implementation_table;
//		| True <<- ("$$$",index_of_type_equivalence_class)

		# ({tei_chosen_type_implementation},type_implementation_table)
			= get_type_implementation index_of_type_equivalence_class type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		| isJust tei_chosen_type_implementation //<<- (tei_chosen_type_implementation)
//			| True <<- "no implementation"
			// an type implementation from the type equivalent class has already been chosen i.e. linked
			= (Just (index_of_type_equivalence_class,created_new_type_equivalence_class),dl_client_state);
//			= abort "stop";

/*
		// examine type equivalent class if it already has been implemented.
		| isTypeWithoutDefinition type1 <<- "implementation"
			| True <<- ("kraai",type1)
			// a type without definition e.g. _List, Int.
//			#! (cs_main_library_instance_i,dl_client_state)
//				= dl_client_state!cs_main_library_instance_i;
//			#! dl_client_state
//				= enter_implementation_type_for_equivalence_class index_of_type_equivalence_class (fromJust cs_main_library_instance_i) dl_client_state;
			= (index_of_type_equivalence_class,created_new_type_equivalence_class,dl_client_state);
			= abort "stoip";
		// The following is assumed for each type equivalent class:
		// - without a chosen type definition, each member of the class must be unimplemented i.e. unlinked.
		// - with a chosen type definition, each member but the chosen must be unimplemented. The chosen
		//   type definition must be implemented i.e. linked.
		//
*/

		| created_new_type_equivalence_class // <<- ("%%%",index_of_type_equivalence_class,type1,type2)
			#! (maybe_type1_implemented,dl_client_state)
				= isTypeImplemented	type1 dl_client_state;
			| isJust maybe_type1_implemented
				#! dl_client_state 
					= dl_client_state //<<- ("type 1 implemented")
				#! dl_client_state
					= enter_implementation_type_for_equivalence_class2 index_of_type_equivalence_class type1 dl_client_state;
				= (Just (index_of_type_equivalence_class,created_new_type_equivalence_class),dl_client_state);

			#! (maybe_type2_implemented,dl_client_state)
				= isTypeImplemented	type2 dl_client_state;
			| isJust maybe_type2_implemented  //<<- "^^"
				#! dl_client_state 
					= dl_client_state //<<- ("type 2 implemented")
				#! dl_client_state
					= enter_implementation_type_for_equivalence_class2 index_of_type_equivalence_class type2 dl_client_state;
				= (Just (index_of_type_equivalence_class,created_new_type_equivalence_class),dl_client_state);
		
			// new type equivalent class has not been implemented
				#! dl_client_state
					= dl_client_state //<<- ("new equiv but only with type equations",type1,type2);
				= (Just (index_of_type_equivalence_class,created_new_type_equivalence_class),dl_client_state);
		
				// type2 is unlinked member of the type equivalent class.
				#! (maybe_type1_implemented,dl_client_state)
					= isTypeImplemented	type1 dl_client_state;
				| isNothing maybe_type1_implemented //<<- ("enter",type1)
					= (Just (index_of_type_equivalence_class,created_new_type_equivalence_class),dl_client_state);
					
					= abort "dkkd";
		
		/*
				| isNothing library_instance_i_implements_type_equivalence_class
					// generate only type equations
					= dl_client_state;
					
					

				# (implementation_type_for_equivalence_class,dl_client_state)
					= getImplementationType ti_reference dl_client_state;
				| isNothing implementation_type_for_equivalence_class
					// given library instance provides the implementation of the type equivalence class
					= enter_implementation_type_for_equivalence_class ti_reference (fromJust library_instance_i_implements_type_equivalence_class) dl_client_state;
					
					= dl_client_state;
		*/
		/*



		= (index_of_type_equivalence_class,created_new_type_equivalence_class,dl_client_state); //abort "stop";
*/
};

// generate the set of label names that implements the type 

/*
get_type_label_names {tio_type_without_definition=Just type_name} type_table_i dl_client_state
	#! list
		= filter (\{pt_type_name} -> type_name == pt_type_name) PredefinedTypes;
	| isEmpty list
		= abort ("get_type_label_names; internal error; unknown predefined type '" +++ type_name +++ "'");

	#! pt_constructor_names
		= map (\label_name -> gen_label_name True (label_name,UnderscoreSystemModule) '?') (hd list).pt_constructor_names;
	= (type_name,pt_constructor_names,dl_client_state);
	
get_type_label_names type_def=:{tio_tr_module_n,tio_tr_type_def_n} type_table_i dl_client_state
	#! (string_table_i,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_type_io_state.tis_string_table;
	#! (tio_module,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_module;
	#! module_name
		= get_name_from_string_table tio_module string_table_i;
		
	// list with constructor names
	#! ({tio_td_name,tio_td_rhs},dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n];
	#! type_name
		= get_name_from_string_table tio_td_name string_table_i;
	#! (label_names,dl_client_state)
		= case tio_td_rhs of {
			(TIO_AlgType defined_symbols)
				-> foldSt (generate_algebraic_type_label_names module_name string_table_i) defined_symbols ([],dl_client_state);
			TIO_RecordType {tio_rt_fields}
				// Hoe kom ik erachter of het record type een index heeft
				-> generate_record_label module_name string_table_i type_name tio_rt_fields dl_client_state;
			TIO_SynType _
				| True <<- ("get_type_label_names; elimination of synonym types should still be done")
				-> ([],dl_client_state); //abort "syntype";
			s
				| True <<- (s,type_name)
				-> abort "lsdfklsfdksdk" <<- s;
		};
//	| True <<- ("labels", label_names)
	= (type_name,label_names,dl_client_state);
where {
	generate_record_label module_name string_table_i record_descriptor_name tio_rt_fields dl_client_state
//		#! record_descriptor_name
//			= get_name_from_string_table tio_td_name string_table_i;

		#! (is_strict_record,dl_client_state)
			= mapASt is_strict_field tio_rt_fields (False,dl_client_state);

		#! r_prefixed_label
			= gen_label_name True (record_descriptor_name,module_name) 'r';
		| is_strict_record <<- (record_descriptor_name)
			// strict
			#! t_prefixed_label
				= gen_label_name True (record_descriptor_name,module_name) 't';
			#! c_prefixed_label
				= gen_label_name True (record_descriptor_name,module_name) 'c';
			= ([r_prefixed_label,t_prefixed_label,c_prefixed_label],dl_client_state);
			
			// non strict record
			= ([r_prefixed_label],dl_client_state);
	where {
		is_strict_field {tio_fs_index} s=:(True,dl_client_state)
			= s;
		is_strict_field {tio_fs_index} (is_strict_record,dl_client_state)
			#! ({tio_st_result={tio_at_annotation}},dl_client_state)
				= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_selector_defs.[tio_fs_index].tio_sd_type;
			#! is_strict_field
				= case tio_at_annotation of {
					TIO_AN_Strict	-> True
					_				-> False
				};
			= (is_strict_record || is_strict_field,dl_client_state);
	};
	

// anySt :: (.a -> .(.b -> (.Bool,.b))) ![.a] .b -> (.Bool,.b);

//		| True <<- tio_cons_type
//		= abort ("algtype " +++ constructor_name) <<- tio_cons_type;
	
/*
TIO_RecordType

::	TIO_RecordType =
	{
		tio_rt_fields			:: !{# TIO_FieldSymbol}
	}
	
::	TIO_FieldSymbol =
	{	tio_fs_name			:: !Int
	,	tio_fs_var			:: !Int				// ?
	,	tio_fs_index		:: !TIO_Index
	}
	
:: TIO_SelectorDef = 
	{ 
		tio_sd_type				:: !TIO_SymbolType
	}

::	TIO_SymbolType =
	{	tio_st_vars			:: ![TIO_TypeVar]
	,	tio_st_args			:: ![TIO_AType]
	,	tio_st_arity		:: !Int
	,	tio_st_result		:: !TIO_AType
	}
*/

	generate_algebraic_type_label_names module_name string_table_i {tio_ds_ident,tio_ds_index} (label_names,dl_client_state)
		#! constructor_name
			= get_name_from_string_table tio_ds_ident string_table_i;
	
		#! (tio_cons_type=:{tio_st_args},dl_client_state)
			= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_cons_defs.[tio_ds_index].tio_cons_type;
		#! is_strict_constructor
			= any is_strict_constructor tio_st_args;
		#! d_prefixed_label
			= gen_label_name True (constructor_name,module_name) 'd';
		| is_strict_constructor // <<- constructor_name
			// strict
			#! k_prefixed_label
				= gen_label_name True (constructor_name,module_name) 'k';
			#! n_prefixed_label
				= gen_label_name True (constructor_name,module_name) 'n';
//			#! l_prefixed_label
//				= gen_label_name True (constructor_name,module_name) 'l';

			#! label_names
				= [k_prefixed_label,d_prefixed_label,n_prefixed_label/*,l_prefixed_label*/:label_names];
			=  (label_names,dl_client_state);

			// non-strict
			#! label_names
				= [d_prefixed_label:label_names];
			=  (label_names,dl_client_state);
	where {
		is_strict_constructor {tio_at_annotation=TIO_AN_Strict}
			= True;
		is_strict_constructor _
			= False;
	};

}

*/

/*
// A type has been implemented iff at least one of its constructors has been linked
has_type_an_implementation type=:(LIT_TypeReference library_instance_i {tio_type_without_definition=Just type_name}) dl_client_state
	#! list
		= filter (\{pt_type_name} -> type_name == pt_type_name) PredefinedTypes;
	| isEmpty list
		= abort "has_type_an_implementation; internal error; unknown predefined type";

	// descriptor names are never underscore prefixed	
	# pt_constructor_names
		= (hd list).pt_constructor_names;
	# (has_type_been_implemented,dl_client_state)
		= anySt (has_constructor_been_implemented UnderscoreSystemModule '?' library_instance_i) pt_constructor_names dl_client_state;
	= (has_type_been_implemented,dl_client_state);

has_type_an_implementation (LIT_TypeReference library_instance_i {tio_tr_module_n,tio_tr_type_def_n}) dl_client_state
	// get module name
	# (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	# (string_table_i,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_type_io_state.tis_string_table;
	# (tio_module,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_module;
	# module_name
		= get_name_from_string_table tio_module string_table_i;
		
	// list with constructor names
	# ({tio_td_name,tio_td_rhs},dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n];
	# constructor_names
		= case tio_td_rhs of {
			(TIO_AlgType defined_symbols)
				-> map (\{tio_ds_ident} -> get_name_from_string_table tio_ds_ident string_table_i) defined_symbols;
			_
				-> abort "has_type_an_implementation (LIT_TypeReference records not implemented";
		};
//	# (has_type_been_implemented,dl_client_state)
//		= anySt (has_constructor_been_implemented UnderscoreSystemModule '?' library_instance_i) pt_constructor_names dl_client_state;
//	= (has_type_been_implemented,dl_client_state);
	| True <<- constructor_names
	= abort ("**** has_type_an_implementation  >>" +++ "aa" +++ module_name +++ " - " ) ;

	has_constructor_been_implemented module_name prefix library_instance_i /* */ constructor_name dl_client_state
		# (li_library_initialized,dl_client_state)
			= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized;
		| not li_library_initialized
			// an uninitialized library instance cannot implement any constructor.
			= (False,dl_client_state);

		// the library instance has been initialized but the constructor may not have been linked into
		// memory.
		#! label_name
			= gen_label_name True (constructor_name,module_name) prefix;

		# (result,dl_client_state)
			= findLabel label_name library_instance_i dl_client_state;
		| isNothing result
			= (False,dl_client_state);
		
		#! (file_n,symbol_n)
			= fromJust result;
		#! (first_symbol_n,dl_client_state)
			= dl_client_state!app_linker_state.marked_offset_a.[file_n];
		#! (marked,dl_client_state)
			=  dl_client_state!app_linker_state.marked_bool_a.[first_symbol_n+symbol_n];
		= (marked,dl_client_state);
	

*/

debug name library_instance_i dl_client_state

	#! (li_library_initialized,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized;
	#! (names_table,dl_client_state)
		= acc_names_table library_instance_i dl_client_state;
	#! (s_names_table,names_table)
		= usize names_table;
	| (s_names_table < 10) <<- ("names_table: " +++ toString (size names_table) +++ " for library instance #" +++ toString library_instance_i +++
	(if (li_library_initialized) "initialized" "not initialzied"))
		= abort ("debug " +++ name);
		
	#! dl_client_state 
		= { dl_client_state & cs_library_instances.lis_library_instances.[library_instance_i].li_names_table = names_table};
	= dl_client_state;

replaceLabel refering_label library_instance_i file_n symbol_n chosen_label_name dl_client_state
	#! ((symbol_hash,ref_file_n,ref_symbol_n,names_table_element_list),dl_client_state)
		= split_symbol_list_in_symbol_table refering_label (\index dl_client_state -> dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_names_table.[index]) dl_client_state;
	#! new_names_table_element
		= NamesTableElement refering_label symbol_n file_n names_table_element_list;
	#! dl_client_state
		= { dl_client_state & 
			cs_library_instances.lis_library_instances.[library_instance_i].li_names_table.[symbol_hash] = new_names_table_element
		};
	// debug ...
	#! msg
		= "replace " +++ refering_label +++ "<" +++ toString ref_file_n +++ "," +++ toString ref_symbol_n +++ "> by " +++
		  chosen_label_name +++ "<" +++ toString file_n +++ "," +++ toString symbol_n +++ ">";
	| True <<- msg
	// ... debug


	// The chosen_label_name which implements a type can be referenced within the defining object module or
	// from some other object module. The latter references are resolved by name using the names table. The
	// former reference by symbol index. These references are accounted for by marking the symbol itself and
	// its defining section (module) as linked and by copying the address of the defining module of the chosen
	// symbol to that referencing module.

	// find module containing referencing symbol	
	#! (ref_module_n,dl_client_state)
		= acc_state (replace_section_label_by_label2 ref_file_n ref_symbol_n) dl_client_state;

	// find module containing chosen symbol
	#! (chosen_symbol,dl_client_state) 
		= dl_client_state!app_linker_state.xcoff_a.[file_n].symbol_table.symbols.[symbol_n];
	#! chosen_module_n
		= case chosen_symbol of {
			Label _ _ module_n 
				-> module_n;
			s
				| True <<- ("***",s)
				-> abort ("unimported label " +++ refering_label );
		};
		
	// compute address of chosen module_n
	#! (chosen_module_n_index,dl_client_state)
		= symbol_n_to_offset file_n chosen_module_n dl_client_state;
	#! (chosen_module_n_address,dl_client_state)
		= dl_client_state!app_linker_state.module_offset_a.[chosen_module_n_index];
	
	// mark referencing module as marked by settings its address to that of the chosen module
	#! (ref_module_n_index,dl_client_state)
		= symbol_n_to_offset ref_file_n ref_module_n dl_client_state;
	#! dl_client_state
		= { dl_client_state &
			app_linker_state.module_offset_a.[ref_module_n_index] 	= chosen_module_n_address
		,	app_linker_state.marked_bool_a.[ref_module_n_index]		= True
		};
		
	#! (ref_symbol_n_index,dl_client_state)
		= symbol_n_to_offset ref_file_n ref_symbol_n dl_client_state;
	#! dl_client_state
		= { dl_client_state &
			app_linker_state.marked_bool_a.[ref_symbol_n_index]		= True
		};
	= dl_client_state;

/*
findLabel :: !String !Int !*DLClientState -> (!Maybe !(!Int,!Int),!*DLClientState);
findLabel label_name library_instance_i dl_client_state
	#! (names_table_element,dl_client_state)
		= find_symbol_in_symbol_table_new label_name (\index dl_client_state -> dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_names_table.[index]) dl_client_state;
	#! label_name_found
		= get names_table_element;
	= (label_name_found,dl_client_state);
where {
	get (NamesTableElement _ symbol_n file_n _)
		= Just (file_n,symbol_n);
	get _
		= Nothing;
};

*/

/*
isLabelImplemented :: !Int !Int !*DLClientState -> (!Maybe !Int,!*DLClientState);
isLabelImplemented file_n symbol_n dl_client_state
	#! (first_symbol_n,dl_client_state)
		= dl_client_state!app_linker_state.marked_offset_a.[file_n];
	#! (marked,dl_client_state)
		=  dl_client_state!app_linker_state.marked_bool_a.[first_symbol_n+symbol_n];
	| not marked
		= (Nothing,dl_client_state);
		
	#! (symbol_address,dl_client_state)
		= acc_state (address_of_label2 file_n symbol_n) dl_client_state;
	= (Just symbol_address,dl_client_state);

*/	

/*

				| isNothing library_instance_i_implements_type_equivalence_class
					// generate only type equations
					= type_implementation_table;
					
					

				# (implementation_type_for_equivalence_class,type_implementation_table)
					= getImplementationType ti_reference type_implementation_table;
				| isNothing implementation_type_for_equivalence_class
					// given library instance provides the implementation of the type equivalence class
					= enter_implementation_type_for_equivalence_class ti_reference (fromJust library_instance_i_implements_type_equivalence_class) type_implementation_table;
					
					= type_implementation_table;

		
					
					
					
				// de library instances moeten nog naar dit nummertje verwijzen.	
			//		| True <<- ("***",ti_reference,"-",ti_reference,left_library_instance_type_ref,right_library_instance_type_ref)
//				= abort "helaas"; //type_implementation_table;

*/








// trivial...
/*
	#! (names_table,dl_client_state)

	get_names_table main_library_instance_i dl_client_state;


	get_library_instances dl_client_state=:{cs_library_instances}
*/

// DLClientState

// ... trivial



/*
acc_library_instances :: .(*LibraryInstances -> *(.a,*LibraryInstances)) !*DLClientState -> *(.a,*DLClientState);
acc_library_instances f dl_client_state=:{cs_library_instances}
	# (x,cs_library_instances)
		= f cs_library_instances;
	= (x,{dl_client_state & cs_library_instances = cs_library_instances});
	
acc_lis_library_instances :: .(*{#*LibraryInstance} -> *(.a,*{#*LibraryInstance})) !*LibraryInstances -> *(.a,*LibraryInstances);
acc_lis_library_instances f cs_library_instances=:{lis_library_instances}
	# (x,lis_library_instances)
		= f lis_library_instances;
	= (x,{cs_library_instances & lis_library_instances = lis_library_instances} );
	
acc_library_instance :: .(*{!NamesTableElement} -> *(.a,*{!NamesTableElement})) !*LibraryInstance -> *(.a,*LibraryInstance);	
acc_library_instance f library_instance=:{li_names_table}
	# (x,li_names_table)
		= f li_names_table;
	= (x,{library_instance & li_names_table = li_names_table});

acc_names_table :: !Int !*DLClientState -> *(.{!NamesTableElement},*DLClientState);	
acc_names_table library_instance_i dl_client_state
	= acc_library_instances (\library_instances -> acc_lis_library_instances select_library_instance library_instances) dl_client_state;
where {
	select_library_instance library_instances 
		# (library_instance,library_instances)
			= replace library_instances library_instance_i default_library_instance;
			
		# (x,library_instance)
			= acc_library_instance (\nt -> (nt,{})) library_instance;
		# library_instances
			= { library_instances & [library_instance_i] = library_instance };
		= (x,library_instances); 
}
*/

instance get_type_implementation DLClientState
where {
	get_type_implementation index_of_type_equivalence_class dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# (implementation_type,type_implementation_table)
			= get_type_implementation index_of_type_equivalence_class type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= (implementation_type,dl_client_state);
};

/*
check_whether_implementation_is_available :: !Int !String !*DLClientState -> (!Bool,!*DLClientState);
check_whether_implementation_is_available library_instance_i label_name dl_client_state
	#! (li_library_initialized,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized;
	| not li_library_initialized
		#! dl_client_state
			= dl_client_state <<- (label_name,False);

		= (False,dl_client_state);
	
	#! (maybe_file_n_symbol_n,dl_client_state)
		= findLabel label_name library_instance_i dl_client_state;
	| isNothing maybe_file_n_symbol_n
		#! dl_client_state
			= dl_client_state <<- (label_name,False);
		= (False,dl_client_state);
		
	#! (file_n,symbol_n)
		= fromJust maybe_file_n_symbol_n;
	#! (maybe_address,dl_client_state)
		= isLabelImplemented file_n symbol_n dl_client_state;
		#! dl_client_state
			= dl_client_state <<- (label_name,True,isJust maybe_address,maybe_address);

	= (isJust maybe_address,dl_client_state);
*/
from DLState import findLabel;
	
/*
isTypeImplemented :: !LibraryInstanceTypeReference !*DLClientState -> (!Maybe !(!String,[String]),*DLClientState);
isTypeImplemented library_instance_type_reference dl_client_state
	#! dl_client_state
		= dl_client_state <<- "-------------";
//	= isTypeImplemented2 allSt library_instance_type_reference dl_client_state;
//NEW2
	= isTypeImplemented2 anySt library_instance_type_reference dl_client_state;

isAnyConstructorOfTypeImplemented :: !LibraryInstanceTypeReference !*DLClientState -> (!Maybe !(!String,[String]),*DLClientState);
isAnyConstructorOfTypeImplemented library_instance_type_reference dl_client_state
	#! dl_client_state
		= dl_client_state <<- "**************";

	= isTypeImplemented2 anySt library_instance_type_reference dl_client_state;

isTypeImplemented2 all_or_any (LIT_TypeReference library_instance_i tio_type_reference=:{tio_type_without_definition=Nothing}) dl_client_state
	#! (li_type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (type_name,labels_implementing_type,dl_client_state)
		= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
	#! dl_client_state
		= dl_client_state <<- ("isTypeImplemented2",labels_implementing_type);
	#! (implementation_is_available,dl_client_state)
		= all_or_any (check_whether_implementation_is_available library_instance_i) labels_implementing_type dl_client_state;	
//		= anySt (check_whether_implementation_is_available library_instance_i) labels_implementing_type dl_client_state;
	| implementation_is_available // <<- ("isTypeImplemented", implementation_is_available, "any=", any_implementation_is_available, library_instance_i, labels_implementing_type)
		= (Just (type_name,labels_implementing_type),dl_client_state);
		= (Nothing,dl_client_state);

isTypeImplemented2 _ (LIT_TypeReference library_instance_i tio_type_reference=:{tio_type_without_definition=Just type_name}) dl_client_state
	#! (li_type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (type_name,labels_implementing_type,dl_client_state)
		= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
	= (Just (type_name,labels_implementing_type),dl_client_state);

*/



class checkTypeEquivalentClass q :: q !*DLClientState -> (!Bool,!*DLClientState);

instance checkTypeEquivalentClass Int // TypeImplementationReference
where {
// checkTypeEquivalentClass :: TypeImplementationReference !*DLClientState -> (!Bool,!*DLClientState);
	checkTypeEquivalentClass type_implementation_ref dl_client_state
		#! ({tei_type_implementations,tei_chosen_type_implementation},dl_client_state)
			= dl_client_state!cs_type_implementation_table.teit_type_implementations_a.[type_implementation_ref];
		| isNothing tei_chosen_type_implementation
			= allSt is_type_unimplemented tei_type_implementations dl_client_state;
			
		#! tei_chosen_type_implementation
			= fromJust tei_chosen_type_implementation;
//		#! tei_type_implementations_should_be_unimplemented
//			= filter ((<>) tei_chosen_type_implementation) tei_type_implementations_should_be_unimplemented;
		#! (types_unimplemented,dl_client_state)
			= allSt is_type_unimplemented tei_type_implementations dl_client_state;
		#! (is_chosen_type_implemented,dl_client_state)
			= isTypeImplemented tei_chosen_type_implementation dl_client_state;
		#! ok
			= (isJust is_chosen_type_implemented) && types_unimplemented;
		= (ok,dl_client_state);
	where {
		is_type_unimplemented library_instance_type_ref dl_client_state
			# (is_implemented,dl_client_state)
				= isTypeImplemented library_instance_type_ref dl_client_state;
			= (isNothing is_implemented,dl_client_state);
	}
};	
	
checkTypeEquivalentClasses :: !*DLClientState -> (!Bool,!*DLClientState);
checkTypeEquivalentClasses dl_client_state
	| True
		= (True,dl_client_state);
		
	#! (teit_n_type_implementations,dl_client_state)
		= dl_client_state!cs_type_implementation_table.teit_n_type_implementations;
	#! (result,dl_client_state)
		= findAst check_type_equivalent_class dl_client_state teit_n_type_implementations;
	| isNothing result
		= (True,dl_client_state);
		= abort ("checkTypeEquivalentClasses; internal error" +++ toString (fromJust result));
where {
	check_type_equivalent_class type_implementation_ref dl_client_state
		#! (ok,dl_client_state)
			= checkTypeEquivalentClass type_implementation_ref dl_client_state;
		| not ok
			= (Just type_implementation_ref,dl_client_state);
		= (Nothing,dl_client_state);
}

	
/*
findAst f s limit :== loopAst 0 limit f s 
where {
	loopAst i limit f s
		| i == limit
			= (Nothing,s);
			
			#! (result,s)
				= f i s;
			| isNothing result
				= loopAst (inc i) limit f s;
				= (result,s);

}
*/
	
		
		
instance add_lazy_type_equations DLClientState
where {
	add_lazy_type_equations index library_instance_type_references dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# type_implementation_table
			= add_lazy_type_equations index library_instance_type_references type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= dl_client_state;
};