implementation module cg_name_mangling;

import StdEnv;

unmangle_name s :== expand_special_chars s;

expand_special_chars :: !String -> !String;
expand_special_chars s
	#! limit
		= size s;
	#! delta
		= count_length_of_expanded_string 0 limit s 0
	| delta == 0
		= s;
		
	#! expanded_label_name_limit
		= limit + delta;
	#! expanded_label_name
		= createArray expanded_label_name_limit ' ';
	= expand_name 0 limit s 0 expanded_label_name
where {
	expand_name :: !Int !Int !String !Int !*{#Char} -> !*{#Char};
	expand_name i limit s j name
		| i == limit
			= name;
			
		#! (delta,name)
			= case s.[i] of {
				'.'		-> (2, { name & [j] = '_', [j+1] = 'P' });
				'_' 	-> (2, { name & [j] = '_', [j+1] = '_' });
				'*' 	-> (2, { name & [j] = '_', [j+1] = 'M' });
				'-' 	-> (2, { name & [j] = '_', [j+1] = 'S' });
				'+' 	-> (2, { name & [j] = '_', [j+1] = 'A' });
				'='		-> (2, { name & [j] = '_', [j+1] = 'E' });
				'~'		-> (2, { name & [j] = '_', [j+1] = 'T' });
				'<'		-> (2, { name & [j] = '_', [j+1] = 'L' });
				'>'		-> (2, { name & [j] = '_', [j+1] = 'G' });
				'/'		-> (2, { name & [j] = '_', [j+1] = 'D' });
				'?'		-> (2, { name & [j] = '_', [j+1] = 'Q' });
				'#'		-> (2, { name & [j] = '_', [j+1] = 'H' });
				':' 	-> (2, { name & [j] = '_', [j+1] = 'C' });
				'$' 	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'D' });
				'^' 	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'C' });
				'@' 	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'T' });
				'&' 	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'A' });
				'%' 	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'P' });
				'\''	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'S' });
				'\"'	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'Q' });
				'|'		-> (2, { name & [j] = '_', [j+1] = 'O' });
				'\\'	-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'B' });
				'`'		-> (2, { name & [j] = '_', [j+1] = 'B' });
				'!'		-> (3, { name & [j] = '_', [j+1] = 'N', [j+2] = 'E' });
				';'		-> (2, { name & [j] = '_', [j+1] = 'I' });
				c		-> (1, { name & [j] = c });
			}
			
		= expand_name (inc i) limit s (j + delta) name;
		

}

mangled_name_length unmangled_name :== count_length_of_expanded_string 0 s_unmangled_name unmangled_name s_unmangled_name;
where {
	s_unmangled_name
		= size unmangled_name;
};

count_length_of_expanded_string :: !Int !Int !String !Int -> !Int;
count_length_of_expanded_string i limit s l
	| i == limit
		= l;
	#! delta
		= case s.[i] of {
			'.'		-> 1;
			'_' 	-> 1;
			'*' 	-> 1;
			'-' 	-> 1;
			'+' 	-> 1;
			'='		-> 1;
			'~'		-> 1;
			'<'		-> 1;
			'>'		-> 1;
			'/'		-> 1;
			'?'		-> 1;
			'#'		-> 1;
			':' 	-> 1;
			'$' 	-> 2;
			'^' 	-> 2;
			'@' 	-> 2;
			'&' 	-> 2;
			'%' 	-> 2;
			'\''	-> 2;
			'\"'	-> 2;
			'|'		-> 1;
			'\\'	-> 2;		
			'`'		-> 1;
			'!'		-> 2;
			';'		-> 1;
			_		-> 0
		}
	= count_length_of_expanded_string (inc i) limit s (l + delta);

// Labels
// Layout:
// e__<mangled module_name>__<prefix><mangled {function,constructor} name}>

// Constants
mangled_module_name_prefix		:== "e__";
s_mangled_module_name_prefix	:== size mangled_module_name_prefix;

mangled_module_name_suffix		:== "__";
s_mangled_module_name_suffix	:== size mangled_module_name_suffix;


class get_label_prefix_from_label s :: !String !Bool !s -> !Char;

instance get_label_prefix_from_label Int
where {
	get_label_prefix_from_label label True s_unmangled_name
		# prefix_start
			= s_mangled_module_name_prefix + s_unmangled_name + s_mangled_module_name_suffix;
		# prefix_end
			= inc prefix_start;
		= (label % (prefix_start,prefix_end)).[0];
};
			
			
