note

	description:

		"Abstract C declarator"

	library: "Eiffel Wrapper Generator Library"
	copyright: "Copyright (c) 1999, Andreas Leitner and others"
	license: "Eiffel Forum License v2 (see forum.txt)"
	date: "$Date$"
	revision: "$Revision$"

class EWG_C_DECLARATION_PROCESSOR

inherit

	EWG_C_AST_TYPE_PROCESSOR

	EWG_PRINTER
		redefine
			make_internal
		end

	KL_IMPORTED_STRING_ROUTINES
		export {NONE} all end

	EWG_SHARED_C_SYSTEM
		export {NONE} all end

	EWG_C_CALLING_CONVENTION_CONSTANTS
		export {NONE} all end



create
	make,
	make_string
	
feature
	make_internal
		do
			reset
		end

feature -- Acccess

	declarator: STRING
			-- Declarator for declaration to generate

feature {EWG_C_AST_TYPE_PROCESSOR} -- Processing

	process_primitive_type (a_type: EWG_C_AST_PRIMITIVE_TYPE)
		do
			if attached a_type.name as l_name then
				output_stream.put_string (l_name)
			end
			if should_print_const then
				output_stream.put_character (' ')
				print_const
			end
			if has_declarator then
				output_stream.put_character (' ')
			end
			print_declarator
		end

	process_eiffel_object_type (a_type: EWG_C_AST_EIFFEL_OBJECT_TYPE)
		do
			process (c_system.types.void_pointer_type)
		end

	process_alias_type (a_type: EWG_C_AST_ALIAS_TYPE)
		do
			if attached a_type.name as l_name then
				output_stream.put_string (l_name)
			end

			if should_print_const then
				output_stream.put_character (' ')
				print_const
			end
			if has_declarator then
				output_stream.put_character (' ')
			end
			print_declarator
		end

	process_pointer_type (a_type: EWG_C_AST_POINTER_TYPE)
		do
			if attached last_type as l_last_type and then l_last_type.is_const_type then
				prepend_to_declarator ("*const ")
			else
				prepend_to_declarator ("*")
			end

			last_type := a_type
			process (a_type.base)
		end

	process_array_type (a_type: EWG_C_AST_ARRAY_TYPE)
		do
			append_to_declarator ("[")
			if attached a_type.size as l_size then
				append_to_declarator (l_size)
			end
			append_to_declarator ("]")
			if should_print_const then
				print_const
				output_stream.put_character (' ')
			end
			last_type := a_type
			process (a_type.base)
		end

	process_const_type (a_type: EWG_C_AST_CONST_TYPE)
		do
			last_type := a_type
			process (a_type.base)
		end

	process_function_type (a_type: EWG_C_AST_FUNCTION_TYPE)
		local
			declaration_printer: EWG_C_DECLARATION_PRINTER
			declaration_list_printer: EWG_C_DECLARATION_LIST_PRINTER
			l_declarator: STRING
		do
			if a_type.calling_convention = stdcall then
				prepend_to_declarator ("__stdcall ")
			elseif a_type.calling_convention = fastcall then
				prepend_to_declarator ("__fastcall ")
			end
			if should_print_const then
				prepend_to_declarator ("const ")
			end
			if attached last_type as l_last_type and then l_last_type.is_pointer_type then
				prepend_to_declarator ("(")
			end
			if attached last_type as l_last_type and then l_last_type.is_pointer_type then
				append_to_declarator (")")
			end
			create declaration_printer.make_string (text_after_declarator)
			create declaration_list_printer.make_string (text_after_declarator, declaration_printer)
			append_to_declarator (" (")
			if	attached a_type.members as l_members then
				declaration_list_printer.print_declaration_list (l_members)
				if a_type.has_ellipsis_parameter then
					append_to_declarator (", ...")
				end
			else
				if not a_type.has_ellipsis_parameter then
					declaration_printer.print_declaration_from_type (c_system.types.void_type, "")
				end
			end
			append_to_declarator (")")
			create l_declarator.make (text_before_declarator.count + declarator.count + text_after_declarator.count)
			l_declarator.append_string (text_before_declarator)
			l_declarator.append_string (declarator)
			l_declarator.append_string (text_after_declarator)
			create declaration_printer.make (output_stream)
			declaration_printer.print_declaration_from_type (a_type.return_type, l_declarator)
		end

	process_struct_type (a_type: EWG_C_AST_STRUCT_TYPE)
		do
			if a_type.is_anonymous then
					check
						has_perfect_alias: a_type.has_perfect_alias_type
					end
				if attached a_type.closest_alias_type as l_closest_alias_type then
					process (l_closest_alias_type)
				end
			else
				output_stream.put_string ("struct ")
				if attached a_type.name as l_name then
					output_stream.put_string (l_name)
				end
--				output_stream.put_string (a_type.name.as_lower)

				if should_print_const then
					output_stream.put_character (' ')
					print_const
				end
				if has_declarator then
					output_stream.put_character (' ')
				end
				print_declarator
			end
		end

	process_union_type (a_type: EWG_C_AST_UNION_TYPE)
		do
			if a_type.is_anonymous then
					check
						has_perfect_alias: a_type.has_perfect_alias_type
					end
				if attached a_type.closest_alias_type as l_closest_alias_type then
					process (l_closest_alias_type)
				end

			else
				output_stream.put_string ("union ")
				if attached a_type.name as l_name then
					output_stream.put_string (l_name)
				end

--				output_stream.put_string (a_type.name.as_lower)
				if should_print_const then
					output_stream.put_character (' ')
					print_const
				end
				if has_declarator then
					output_stream.put_character (' ')
				end
				print_declarator
			end
		end

	process_enum_type (a_type: EWG_C_AST_ENUM_TYPE)
		do
			if a_type.is_anonymous then
					check
						has_perfect_alias: a_type.has_perfect_alias_type
					end
				if attached a_type.closest_alias_type as l_closest_alias_type then
					process (l_closest_alias_type)
				end
			else
				output_stream.put_string ("enum ")
				if attached a_type.name as l_name  then
					output_stream.put_string (l_name)
				end
				if should_print_const then
					output_stream.put_character (' ')
					print_const
				end
				if has_declarator then
					output_stream.put_character (' ')
				end
				print_declarator
			end
		end

feature {NONE}

	text_before_declarator: STRING
			-- Text to output before `declarator'

	text_after_declarator: STRING
			-- Text to output after  `declarator'

	reset
		do
			create declarator.make_empty
			create text_after_declarator.make_empty
			create text_before_declarator.make_empty
			last_type := Void
		ensure
			declarator_not_void: declarator /= Void
			declarator_is_empty: declarator.count = 0
			text_before_declarator_not_void: text_before_declarator /= Void
			text_before_declarator_is_empty: text_before_declarator.count = 0
			text_after_declarator_not_void: text_after_declarator /= Void
			text_after_declarator_is_empty: text_after_declarator.count = 0
		end

	last_type: detachable EWG_C_AST_TYPE
			-- Last type that was processed

	process (a_type: EWG_C_AST_TYPE)
			-- Process `a_type'.
		require
			a_type_not_void: a_type /= Void
			a_type_valid: a_type.is_named_recursive or a_type.based_type_recursive.is_function_type or a_type.based_type_recursive.is_eiffel_object_type or a_type.based_type_recursive.has_perfect_alias_type
			declarator_not_void: declarator /= Void
		do
			a_type.process (Current)
		end

	prepend_to_declarator (a_string: STRING)
			-- Prepend `a_string' to `text_before_declarator'.
		require
			a_string_not_void: a_string /= Void
			a_string_not_empty: a_string.count > 0
			text_before_declarator_not_void: text_before_declarator /= Void
		local
			new_text_before_declarator: STRING
		do
			create new_text_before_declarator.make (a_string.count + text_before_declarator.count)
			new_text_before_declarator.append_string (a_string)
			new_text_before_declarator.append_string (text_before_declarator)
			text_before_declarator := new_text_before_declarator
		ensure
			text_before_declarator_size: text_before_declarator.count = a_string.count + old text_before_declarator.count
			a_string_prepended: STRING_.same_string (text_before_declarator.substring (1, a_string.count), a_string)
			old_string_follows: STRING_.same_string (text_before_declarator.substring (a_string.count + 1, text_before_declarator.count), old text_before_declarator.twin)
		end

	append_to_declarator (a_string: STRING)
			-- Append `a_string' to `text_after_declarator'.
		require
			a_string_not_void: a_string /= Void
			a_string_not_empty: a_string.count > 0
			text_after_declarator_not_void: text_after_declarator /= Void
		do
			text_after_declarator.append_string (a_string)
		ensure
			text_after_declarator_size: text_after_declarator.count = a_string.count + old text_after_declarator.count
		end

	print_declarator
		require
			text_before_declarator_not_void: text_before_declarator /= Void
			text_after_declarator_not_void: text_after_declarator /= Void
			declarator_not_void: declarator /= Void
		do
			output_stream.put_string (text_before_declarator)
			output_stream.put_string (declarator)
			output_stream.put_string (text_after_declarator)
		end

	print_const
			-- Print "const".
		require
			should_print_const
		do
			output_stream.put_string ("const")
		end

	should_print_const: BOOLEAN
		do
			Result := attached last_type as l_last_type and then l_last_type.is_const_type
		end

	has_declarator: BOOLEAN
		require
			declarator_not_void: declarator /= Void
		do
			Result := declarator.count > 0
		end

end