note
	description: "[
					Roundtrip visitor to simply iterate an AST tree and do nothing
					Usage:
						There are two things that you have to do:
							1. invoke `set_parsed_class' to set on which class this visitor should work
							2. invoke `set_match_list' bacause a LEAF_AS_LIST is needed for roundtrip visiting
						And two things you may need to do:
							1. invoke `set_will_process_leading_leaves' to let the visitor process leading breaks and optional semicolons
							2. invoke `set_will_process_trailing_leaves' to let the visitor process trailing breaks
						or you can call `setup' to do all the things at one time.
					Note: 1. Always `call process_ast_node' to process an AST node, do not use process_xxx directly.
						  2. `process_leading_leaves' and `process_trailing_leaves' are designed to deal with
						  	 non-attached terminals (For more information, see `LEAF_AS_LIST') to make sure they can be
						  	 processed correctly. Before we process every attached terminal, we check if there is any
						  	 non-attached terminal that has not been processed, if so, we process those terminals first. And after we
						  	 have process the last attached-terminal, we check any non-attached terminals have been left, if so,
						  	 we process thoes as well.
				]"

class
	AST_ROUNDTRIP_ITERATOR

inherit
	AST_VISITOR
		redefine
			is_valid
		end

feature -- Status report

	is_valid: BOOLEAN
		do
			Result := parsed_class /= Void and then internal_match_list /= Void
		end

feature -- AST process

	process_ast_node (a_node: AST_EIFFEL)
			-- Process `a_node'.
			-- Note: `a_node' must be included in `parsed_class'.
		require
			is_valid: is_valid
		do
			if
				attached match_list.item_by_start_position (a_node.complete_start_position (match_list)) as l_start_leaf and then
				attached match_list.item_by_end_position (a_node.complete_end_position (match_list)) as l_end_leaf
			then
				start_index := l_start_leaf.index
				end_index := l_end_leaf.index
			end
			last_index := start_index - 1
			safe_process (a_node)
			process_trailing_leaves
		end

feature -- Access

	parsed_class: detachable CLASS_AS
			-- Roundtrip-parsed class
			-- All iteration will be conducted within the scope of this class.

	last_index: INTEGER
			-- Index of last processed item in `match_list'.

	start_index: INTEGER
	end_index: INTEGER
			-- Start and end item index in `match_list'.

	match_list: LEAF_AS_LIST
			-- List of tokens
		require
			is_valid: is_valid
		do
			check attached internal_match_list as l_list then
				Result := l_list
			end
		end

	will_process_leading_leaves: BOOLEAN
			-- Will leading ast nodes (BREAK_AS or SYMBOL_AS:optional semicolon) be processed?	

	will_process_trailing_leaves: BOOLEAN
			-- Will trailing ast nodes (BREAK_AS) be processed?

feature -- Settings

	reset
			-- Reset current
		do
			parsed_class := Void
			internal_match_list := Void
		end

	setup (a_class: CLASS_AS; a_list: LEAF_AS_LIST; will_process_leading, will_process_trailing: BOOLEAN)
			-- Setup environment for roundtrip visit.
		require
			a_class_not_void: a_class /= Void
			a_list_not_void: a_list /= Void
		do
			set_parsed_class (a_class)
			set_match_list (a_list)
			set_will_process_leading_leaves (will_process_leading)
			set_will_process_trailing_leaves (will_process_trailing)
		ensure
			is_valid: is_valid
		end

	set_parsed_class (a_class: CLASS_AS)
			-- Set `parsed_class' with `a_class'.
		require
			a_class_not_void: a_class /= Void
		do
			parsed_class := a_class
			last_index := 0
			start_index := 1
		ensure
			parsed_class_set: parsed_class = a_class
		end

	set_match_list (a_list: LEAF_AS_LIST)
			-- Set `match_list' with `a_list'.
		require
			a_list_not_void: a_list /= Void
		do
			internal_match_list := a_list
			end_index := a_list.count
		ensure
			match_list_set: internal_match_list = a_list
		end

	set_will_process_leading_leaves (b: BOOLEAN)
			-- Set `will_process_leading_leaves' with `b'.
		do
			will_process_leading_leaves := b
		ensure
			will_process_leading_leaves_set: will_process_leading_leaves = b
		end

	set_will_process_trailing_leaves (b: BOOLEAN)
			-- Set `will_process_trailing_leaves' with `b'.
		do
			will_process_trailing_leaves := b
		ensure
			will_process_trailing_leaves_set: will_process_trailing_leaves = b
		end

feature -- Roundtrip: process leaf

	process_keyword_as (l_as: KEYWORD_AS)
			-- Process `l_as'.
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_symbol_as (l_as: SYMBOL_AS)
			-- Process `l_as'.
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_break_as (l_as: BREAK_AS)
			-- Process `l_as'.			
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_leaf_stub_as (l_as: LEAF_STUB_AS)
			-- Process `l_as'.
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_symbol_stub_as (l_as: SYMBOL_STUB_AS)
			-- Process `l_as'.
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_keyword_stub_as (l_as: KEYWORD_STUB_AS)
			-- Process `l_as'.
		do
			process_keyword_as (l_as)
		end

	process_bool_as (l_as: BOOL_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_char_as (l_as: CHAR_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_result_as (l_as: RESULT_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_retry_as (l_as: RETRY_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_unique_as (l_as: UNIQUE_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_deferred_as (l_as: DEFERRED_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_void_as (l_as: VOID_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_string_as (l_as: STRING_AS)
		do
			if l_as.is_once_string then
				safe_process (l_as.once_string_keyword (match_list))
			end
			safe_process (l_as.type)
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_verbatim_string_as (l_as: VERBATIM_STRING_AS)
		do
			if l_as.is_once_string then
				safe_process (l_as.once_string_keyword (match_list))
			end
			safe_process (l_as.type)
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_current_as (l_as: CURRENT_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_integer_as (l_as: INTEGER_AS)
		do
			safe_process (l_as.constant_type)
			safe_process (l_as.sign_symbol (match_list))
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_real_as (l_as: REAL_AS)
		do
			safe_process (l_as.constant_type)
			safe_process (l_as.sign_symbol (match_list))
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_id_as (l_as: ID_AS)
		do
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

feature

	process_none_id_as (l_as: NONE_ID_AS)
			-- Process `l_as'.
		do
			-- Do nothing, because this id is automatically inserted by Eiffel compiler,
			-- we should not produce it when doing roundtrip.
		end

	process_typed_char_as (l_as: TYPED_CHAR_AS)
			-- Process `l_as'.
		do
			l_as.type.process (Current)
			process_leading_leaves (l_as.index)
			last_index := l_as.index
		end

	process_agent_routine_creation_as (l_as: AGENT_ROUTINE_CREATION_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.agent_keyword (match_list))
			if l_as.target /= Void then
				safe_process (l_as.lparan_symbol (match_list))
				safe_process (l_as.target)
				safe_process (l_as.rparan_symbol (match_list))
				safe_process (l_as.dot_symbol (match_list))
			end
			safe_process (l_as.feature_name)
			safe_process (l_as.internal_operands)
		end

	process_inline_agent_creation_as (l_as: INLINE_AGENT_CREATION_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.agent_keyword (match_list))
			safe_process (l_as.body)
			safe_process (l_as.internal_operands)
		end

	process_creation_as (l_as: CREATION_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.create_keyword (match_list))
			safe_process (l_as.type)
			safe_process (l_as.target)
			safe_process (l_as.call)
		end

	process_creation_expr_as (l_as: CREATION_EXPR_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.create_keyword (match_list))
			safe_process (l_as.type)
			safe_process (l_as.call)
		end

feature

	process_custom_attribute_as (l_as: CUSTOM_ATTRIBUTE_AS)
		do
			safe_process (l_as.creation_expr)
			safe_process (l_as.tuple)
			safe_process (l_as.end_keyword (match_list))
		end

	process_static_access_as (l_as: STATIC_ACCESS_AS)
		do
			safe_process (l_as.feature_keyword (match_list))
			safe_process (l_as.class_type)
			safe_process (l_as.dot_symbol (match_list))
			safe_process (l_as.feature_name)
			safe_process (l_as.internal_parameters)
		end

	process_feature_clause_as (l_as: FEATURE_CLAUSE_AS)
		do
			safe_process (l_as.feature_keyword)
			safe_process (l_as.clients)
			safe_process (l_as.features)
		end

	process_tuple_as (l_as: TUPLE_AS)
		do
			safe_process (l_as.lbracket_symbol (match_list))
			safe_process (l_as.expressions)
			safe_process (l_as.rbracket_symbol (match_list))
		end

	process_array_as (l_as: ARRAY_AS)
		do
			safe_process (l_as.type)
			safe_process (l_as.larray_symbol (match_list))
			safe_process (l_as.expressions)
			safe_process (l_as.rarray_symbol (match_list))
		end

	process_body_as (l_as: BODY_AS)
		do
			safe_process (l_as.internal_arguments)
			safe_process (l_as.colon_symbol (match_list))
			safe_process (l_as.type)
			safe_process (l_as.assign_keyword (match_list))
			safe_process (l_as.assigner)
			safe_process (l_as.is_keyword (match_list))

			if attached {CONSTANT_AS} l_as.content as c_as then
				c_as.process (Current)
				safe_process (l_as.indexing_clause)
			else
				safe_process (l_as.indexing_clause)
				safe_process (l_as.content)
			end
		end

	process_built_in_as (l_as: BUILT_IN_AS)
			-- Process `l_as'.
		do
			process_external_as (l_as)
		end

	process_access_feat_as (l_as: ACCESS_FEAT_AS)
		do
			safe_process (l_as.feature_name)
			safe_process (l_as.internal_parameters)
		end

	process_access_inv_as (l_as: ACCESS_INV_AS)
		do
			safe_process (l_as.dot_symbol (match_list))
			safe_process (l_as.feature_name)
			safe_process (l_as.internal_parameters)
		end

	process_access_id_as (l_as: ACCESS_ID_AS)
		do
			safe_process (l_as.feature_name)
			safe_process (l_as.internal_parameters)
		end

	process_access_assert_as (l_as: ACCESS_ASSERT_AS)
		do
			process_access_feat_as (l_as)
		end

	process_precursor_as (l_as: PRECURSOR_AS)
		do
			safe_process (l_as.precursor_keyword)
			safe_process (l_as.parent_base_class)
			safe_process (l_as.internal_parameters)
		end

	process_nested_expr_as (l_as: NESTED_EXPR_AS)
		do
			safe_process (l_as.target)
			safe_process (l_as.dot_symbol (match_list))
			safe_process (l_as.message)
		end

	process_type_expr_as (l_as: TYPE_EXPR_AS)
		do
			safe_process (l_as.type)
		end

	process_routine_as (l_as: ROUTINE_AS)
		do

			safe_process (l_as.obsolete_keyword (match_list))
			safe_process (l_as.obsolete_message)
			safe_process (l_as.precondition)
			safe_process (l_as.internal_locals)
			safe_process (l_as.routine_body)
			safe_process (l_as.postcondition)
			safe_process (l_as.rescue_keyword (match_list))
			safe_process (l_as.rescue_clause)
			safe_process (l_as.end_keyword)
		end

	process_constant_as (l_as: CONSTANT_AS)
		do
			safe_process (l_as.value)
		end

	process_eiffel_list (l_as: EIFFEL_LIST [AST_EIFFEL])
		local
			i: INTEGER
			j: INTEGER
			n: INTEGER
			m: INTEGER
		do
			from
				n := l_as.count
				i := 1
				check
					consistent_separator_count: attached l_as.separator_list as l implies l.count = n or else l.count = n - 1
				end
				if attached l_as.separator_list as l_sep_list then
					m := l_sep_list.count
					if m >= n then
							-- There is a leading separator, start from index 1.
						j := 1
					end
				else
					m := 0
				end
			until
				i > n
			loop
				if j = 0 then
						-- There is no leading separator, advance to the next one.
					j := 1
				elseif j <= m then
						-- There is a separator, process it.
					safe_process (l_as.separator_list_i_th (j, match_list))
					j := j + 1
				end
					-- Process list element.
				safe_process (l_as [i])
				i := i + 1
			end
		end

	process_indexing_clause_as (l_as: INDEXING_CLAUSE_AS)
		do
			safe_process (l_as.indexing_keyword (match_list))
			process_eiffel_list (l_as)
			safe_process (l_as.end_keyword (match_list))
		end

	process_operand_as (l_as: OPERAND_AS)
		do
			safe_process (l_as.class_type)
			safe_process (l_as.question_mark_symbol (match_list))
			safe_process (l_as.expression)
		end

	process_tagged_as (l_as: TAGGED_AS)
		do
			safe_process (l_as.tag)
			safe_process (l_as.colon_symbol (match_list))
			safe_process (l_as.class_keyword (match_list))
			safe_process (l_as.expr)
		end

	process_variant_as (l_as: VARIANT_AS)
		do
			safe_process (l_as.variant_keyword (match_list))
			safe_process (l_as.tag)
			safe_process (l_as.colon_symbol (match_list))
			safe_process (l_as.expr)
		end

	process_un_strip_as (l_as: UN_STRIP_AS)
		do
			safe_process (l_as.strip_keyword (match_list))
			safe_process (l_as.lparan_symbol (match_list))
			process_identifier_list (l_as.id_list)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_converted_expr_as (l_as: CONVERTED_EXPR_AS)
		do
			l_as.expr.process (Current)
		end

	process_paran_as (l_as: PARAN_AS)
		do
			safe_process (l_as.lparan_symbol (match_list))
			l_as.expr.process (Current)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_expr_call_as (l_as: EXPR_CALL_AS)
		do
			l_as.call.process (Current)
		end

	process_expr_address_as (l_as: EXPR_ADDRESS_AS)
		do
			safe_process (l_as.address_symbol (match_list))
			safe_process (l_as.lparan_symbol (match_list))
			safe_process (l_as.expr)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_address_result_as (l_as: ADDRESS_RESULT_AS)
		do
			safe_process (l_as.address_symbol (match_list))
			safe_process (l_as.result_keyword)
		end

	process_address_current_as (l_as: ADDRESS_CURRENT_AS)
		do
			safe_process (l_as.address_symbol (match_list))
			safe_process (l_as.current_keyword)
		end

	process_address_as (l_as: ADDRESS_AS)
		do
			safe_process (l_as.address_symbol (match_list))
			safe_process (l_as.feature_name)
		end

	process_predecessor_as (a: PREDECESSOR_AS)
			-- <Precursor>
		do
			safe_process (a.predecessor_symbol (match_list))
			safe_process (a.name)
		end

	process_routine_creation_as (l_as: ROUTINE_CREATION_AS)
		do
			check
				should_not_reach_here: False
			end
		end

	process_unary_as (l_as: UNARY_AS)
		do
			safe_process (l_as.operator (match_list))
			safe_process (l_as.expr)
		end

	process_un_free_as (l_as: UN_FREE_AS)
		do
			safe_process (l_as.op_name)
			safe_process (l_as.expr)
		end

	process_un_minus_as (l_as: UN_MINUS_AS)
		do
			process_unary_as (l_as)
		end

	process_un_not_as (l_as: UN_NOT_AS)
		do
			process_unary_as (l_as)
		end

	process_un_old_as (l_as: UN_OLD_AS)
		do
			process_unary_as (l_as)
		end

	process_un_plus_as (l_as: UN_PLUS_AS)
		do
			process_unary_as (l_as)
		end

	process_binary_as (l_as: BINARY_AS)
		do
			safe_process (l_as.left)
			safe_process (l_as.operator (match_list))
			safe_process (l_as.right)
		end

	process_bin_and_then_as (l_as: BIN_AND_THEN_AS)
		do
			safe_process (l_as.left)
			safe_process (l_as.and_keyword (match_list))
			safe_process (l_as.then_keyword (match_list))
			safe_process (l_as.right)
		end

	process_bin_free_as (l_as: BIN_FREE_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_implies_as (l_as: BIN_IMPLIES_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_or_as (l_as: BIN_OR_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_or_else_as (l_as: BIN_OR_ELSE_AS)
		do
			safe_process (l_as.left)
			safe_process (l_as.or_keyword (match_list))
			safe_process (l_as.else_keyword (match_list))
			safe_process (l_as.right)
		end

	process_bin_xor_as (l_as: BIN_XOR_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_ge_as (l_as: BIN_GE_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_gt_as (l_as: BIN_GT_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_le_as (l_as: BIN_LE_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_lt_as (l_as: BIN_LT_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_div_as (l_as: BIN_DIV_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_minus_as (l_as: BIN_MINUS_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_mod_as (l_as: BIN_MOD_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_plus_as (l_as: BIN_PLUS_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_power_as (l_as: BIN_POWER_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_slash_as (l_as: BIN_SLASH_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_star_as (l_as: BIN_STAR_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_and_as (l_as: BIN_AND_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_eq_as (l_as: BIN_EQ_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_ne_as (l_as: BIN_NE_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_tilde_as (l_as: BIN_TILDE_AS)
		do
			process_binary_as (l_as)
		end

	process_bin_not_tilde_as (l_as: BIN_NOT_TILDE_AS)
		do
			process_binary_as (l_as)
		end

	process_bracket_as (l_as: BRACKET_AS)
		do
			safe_process (l_as.target)
			safe_process (l_as.lbracket_symbol)
			safe_process (l_as.operands)
			safe_process (l_as.rbracket_symbol)
		end

	process_object_test_as (l_as: OBJECT_TEST_AS)
		do
			if l_as.is_attached_keyword then
				safe_process (l_as.attached_keyword (match_list))
				safe_process (l_as.type)
				l_as.expression.process (Current)
				safe_process (l_as.as_keyword (match_list))
				safe_process (l_as.name)
			else
				safe_process (l_as.lcurly_symbol (match_list))
				safe_process (l_as.name)
				safe_process (l_as.type)
				l_as.expression.process (Current)
			end
		end

	process_external_lang_as (l_as: EXTERNAL_LANG_AS)
		do
			l_as.language_name.process (Current)
		end

	process_feature_as (l_as: FEATURE_AS)
		do
			safe_process (l_as.feature_names)
			safe_process (l_as.body)
		end

	process_feature_name (l_as: FEATURE_NAME)
		do
			safe_process (l_as.frozen_keyword)
			safe_process (l_as.feature_name)
		end

	process_feature_name_alias_as (l_as: FEATURE_NAME_ALIAS_AS)
		do
			safe_process (l_as.frozen_keyword)
			safe_process (l_as.feature_name)
			across
				l_as.aliases as ic
			loop
				safe_process (l_as.keyword_at (match_list, ic.alias_keyword_index))
				safe_process (ic.alias_name)
			end
			if l_as.convert_keyword_index > 0 then
				safe_process (l_as.convert_keyword (match_list))
			end

		end

	process_feature_list_as (l_as: FEATURE_LIST_AS)
		do
			safe_process (l_as.features)
		end

	process_all_as (l_as: ALL_AS)
		do
			safe_process (l_as.all_keyword (match_list))
		end

	process_assign_as (l_as: ASSIGN_AS)
		do
			safe_process (l_as.target)
			safe_process (l_as.assignment_symbol (match_list))
			safe_process (l_as.source)
		end

	process_assigner_call_as (l_as: ASSIGNER_CALL_AS)
		do
			safe_process (l_as.target)
			safe_process (l_as.assignment_symbol)
			safe_process (l_as.source)
		end

	process_reverse_as (l_as: REVERSE_AS)
		do
			safe_process (l_as.target)
			safe_process (l_as.assignment_symbol (match_list))
			safe_process (l_as.source)
		end

	process_check_as (l_as: CHECK_AS)
		do
			safe_process (l_as.check_keyword (match_list))
			safe_process (l_as.full_assertion_list)
			safe_process (l_as.end_keyword)
		end

	process_debug_as (l_as: DEBUG_AS)
		do
			safe_process (l_as.debug_keyword (match_list))
			safe_process (l_as.internal_keys)
			safe_process (l_as.compound)
			safe_process (l_as.end_keyword)
		end

	process_guard_as (l_as: GUARD_AS)
		do
			safe_process (l_as.check_keyword (match_list))
			safe_process (l_as.full_assertion_list)
			safe_process (l_as.then_keyword (match_list))
			safe_process (l_as.compound)
			safe_process (l_as.end_keyword)
		end

	process_if_as (l_as: IF_AS)
		do
			safe_process (l_as.if_keyword (match_list))
			safe_process (l_as.condition)
			safe_process (l_as.then_keyword (match_list))
			safe_process (l_as.compound)
			safe_process (l_as.elsif_list)
			safe_process (l_as.else_keyword (match_list))
			safe_process (l_as.else_part)
			safe_process (l_as.end_keyword)
		end

	process_if_expression_as (l_as: IF_EXPRESSION_AS)
		do
			safe_process (l_as.if_keyword (match_list))
			l_as.condition.process (Current)
			safe_process (l_as.then_keyword (match_list))
			l_as.then_expression.process (Current)
			safe_process (l_as.elsif_list)
			safe_process (l_as.else_keyword (match_list))
			l_as.else_expression.process (Current)
			safe_process (l_as.end_keyword)
		end

	process_inspect_abstraction (a: INSPECT_ABSTRACTION_AS [CASE_ABSTRACTION_AS [detachable AST_EIFFEL], detachable AST_EIFFEL])
			-- Process `a`.
		do
			safe_process (a.inspect_keyword (match_list))
			safe_process (a.switch)
			safe_process (a.case_list)
			safe_process (a.else_keyword (match_list))
			safe_process (a.else_part)
			safe_process (a.end_keyword)
		end

	process_inspect_as (a: INSPECT_AS)
		do
			process_inspect_abstraction (a)
		end

	process_inspect_expression_as (a: INSPECT_EXPRESSION_AS)
		do
			process_inspect_abstraction (a)
		end

	process_instr_call_as (l_as: INSTR_CALL_AS)
		do
			l_as.call.process (Current)
		end

	process_loop_as (l_as: LOOP_AS)
		local
			l_until: detachable KEYWORD_AS
			l_variant_processing_after: BOOLEAN
			l_variant_part: detachable VARIANT_AS
			i: ITERATION_AS
		do
			i := l_as.iteration
			if attached i and then i.is_symbolic then
					-- The loop is of the form
					-- ⟳ var: expr ¦ compound ⟲
				safe_process (l_as.repeat_symbol (match_list))
				i.process (Current)
				safe_process (l_as.compound)
				safe_process (l_as.end_symbol)
			else
				safe_process (i)
				safe_process (l_as.from_keyword (match_list))
				safe_process (l_as.from_part)
				safe_process (l_as.invariant_keyword (match_list))
				safe_process (l_as.full_invariant_list)
					-- Special code to handle the old or new ordering of the `variant'
					-- clause in a loop.
				l_until := l_as.until_keyword (match_list)
				l_variant_part := l_as.variant_part
				if l_until = Void then
						-- Must be across loop
					l_variant_processing_after := True
				elseif l_variant_part /= Void then
					if l_variant_part.start_position > l_until.start_position then
						l_variant_processing_after := True
					else
						l_variant_part.process (Current)
					end
				end
				safe_process (l_until)
				safe_process (l_as.stop)
				safe_process (l_as.loop_keyword (match_list))
				safe_process (l_as.compound)
				if l_variant_part /= Void and l_variant_processing_after then
					l_variant_part.process (Current)
				end
				safe_process (l_as.end_keyword)
			end
		end

	process_iteration_as (a: ITERATION_AS)
			-- <Precursor>
		do
			if a.is_symbolic then
				a.identifier.process (Current)
				safe_process (a.in_symbol (match_list))
				a.expression.process (Current)
				safe_process (a.bar_symbol (match_list))
			else
				safe_process (a.across_keyword (match_list))
				a.expression.process (Current)
				safe_process (a.as_keyword (match_list))
				a.identifier.process (Current)
			end
		end

	process_loop_expr_as (l_as: LOOP_EXPR_AS)
		local
			i: ITERATION_AS
		do
			i := l_as.iteration
			if i.is_symbolic then
					-- The loop is of the form
					-- ∀ var: expr | expr
				safe_process (l_as.qualifier_symbol (match_list))
				i.process (Current)
				l_as.expression.process (Current)
			else
					-- The loop is of the form
					-- across expr as var [invariant expr] [until expr] all expr [variant expr] end
				i.process (Current)
				safe_process (l_as.invariant_keyword (match_list))
				safe_process (l_as.full_invariant_list)
				safe_process (l_as.until_keyword (match_list))
				safe_process (l_as.exit_condition)
				safe_process (l_as.qualifier_keyword (match_list))
				l_as.expression.process (Current)
				safe_process (l_as.variant_part)
				safe_process (l_as.end_keyword)
			end
		end

	process_separate_instruction_as (a: SEPARATE_INSTRUCTION_AS)
			-- <Precursor>
		do
			safe_process (a.separate_keyword (match_list))
			a.arguments.process (Current)
			safe_process (a.do_keyword (match_list))
			safe_process (a.compound)
			a.end_keyword.process (Current)
		end

	process_external_as (l_as: EXTERNAL_AS)
		do
			safe_process (l_as.external_keyword (match_list))
			safe_process (l_as.language_name)
			safe_process (l_as.alias_keyword (match_list))
			safe_process (l_as.alias_name_literal)
		end

	process_attribute_as (l_as: ATTRIBUTE_AS)
		do
			safe_process (l_as.attribute_keyword (match_list))
			safe_process (l_as.compound)
		end

	process_do_as (l_as: DO_AS)
		do
			safe_process (l_as.do_keyword (match_list))
			safe_process (l_as.compound)
		end

	process_once_as (l_as: ONCE_AS)
		do
			safe_process (l_as.once_keyword (match_list))
			safe_process (l_as.internal_keys)
			safe_process (l_as.compound)
		end

	process_list_dec_as (l_as: LIST_DEC_AS)
		do
			process_identifier_list (l_as.id_list)
		end

	process_type_dec_as (l_as: TYPE_DEC_AS)
		do
			process_identifier_list (l_as.id_list)
			safe_process (l_as.colon_symbol (match_list))
			safe_process (l_as.type)
		end

	process_class_as (l_as: CLASS_AS)
		do
			safe_process (l_as.internal_top_indexes)
			safe_process (l_as.frozen_keyword (match_list))
			safe_process (l_as.deferred_keyword (match_list))
			safe_process (l_as.expanded_keyword (match_list))
			safe_process (l_as.once_keyword (match_list))
			safe_process (l_as.external_keyword (match_list))
			safe_process (l_as.class_keyword (match_list))
			safe_process (l_as.class_name)
			safe_process (l_as.internal_generics)
			safe_process (l_as.alias_keyword (match_list))
			safe_process (l_as.external_class_name)
			safe_process (l_as.obsolete_keyword (match_list))
			safe_process (l_as.obsolete_message)
			safe_process (l_as.internal_conforming_parents)
			safe_process (l_as.internal_non_conforming_parents)
			safe_process (l_as.creators)
			safe_process (l_as.convertors)
			safe_process (l_as.features)
			safe_process (l_as.internal_invariant)
			safe_process (l_as.internal_bottom_indexes)
			safe_process (l_as.end_keyword)
		end

	process_parent_as (l_as: PARENT_AS)
		do
			safe_process (l_as.type)
			safe_process (l_as.internal_renaming)
			safe_process (l_as.internal_exports)
			safe_process (l_as.internal_undefining)
			safe_process (l_as.internal_redefining)
			safe_process (l_as.internal_selecting)
			safe_process (l_as.end_keyword (match_list))
		end

	process_like_id_as (l_as: LIKE_ID_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.like_keyword (match_list))
			safe_process (l_as.anchor)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_like_cur_as (l_as: LIKE_CUR_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.like_keyword (match_list))
			safe_process (l_as.current_keyword)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_qualified_anchored_type_as (l_as: QUALIFIED_ANCHORED_TYPE_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.like_keyword (match_list))
			safe_process (l_as.qualifier)
			safe_process (l_as.chain)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_feature_id_as (l_as: FEATURE_ID_AS)
			-- <Precursor>
		do
			safe_process (l_as.name)
		end

	process_formal_as (l_as: FORMAL_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.formal_keyword (match_list))
			safe_process (l_as.name)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_formal_dec_as (l_as: FORMAL_DEC_AS)
		do
			safe_process (l_as.formal)
			safe_process (l_as.constrain_symbol (match_list))
			safe_process (l_as.constraints)
			safe_process (l_as.create_keyword (match_list))
			safe_process (l_as.creation_feature_list)
			safe_process (l_as.end_keyword (match_list))
		end

	process_class_type_as (l_as: CLASS_TYPE_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.expanded_keyword (match_list))
			safe_process (l_as.separate_keyword (match_list))
			safe_process (l_as.class_name)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_generic_class_type_as (l_as: GENERIC_CLASS_TYPE_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.expanded_keyword (match_list))
			safe_process (l_as.separate_keyword (match_list))
			safe_process (l_as.class_name)
			safe_process (l_as.internal_generics)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_named_tuple_type_as (l_as: NAMED_TUPLE_TYPE_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.attachment_mark (match_list))
			safe_process (l_as.separate_keyword (match_list))
			safe_process (l_as.class_name)
			safe_process (l_as.parameters)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_constraining_type_as (l_as: CONSTRAINING_TYPE_AS)
		do
			l_as.type.process (Current)
			safe_process (l_as.renaming)
			safe_process (l_as.end_keyword (match_list))
		end

	process_none_type_as (l_as: NONE_TYPE_AS)
		do
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.class_name_literal)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_rename_as (l_as: RENAME_AS)
		do
			safe_process (l_as.old_name)
			safe_process (l_as.as_keyword (match_list))
			safe_process (l_as.new_name)
		end

	process_invariant_as (l_as: INVARIANT_AS)
		do
			safe_process (l_as.invariant_keyword (match_list))
			safe_process (l_as.full_assertion_list)
		end

	process_interval_as (l_as: INTERVAL_AS)
		do
			safe_process (l_as.lower)
			safe_process (l_as.dotdot_symbol)
			safe_process (l_as.upper)
		end

	process_index_as (l_as: INDEX_AS)
		do
			safe_process (l_as.tag)
			safe_process (l_as.colon_symbol (match_list))
			safe_process (l_as.index_list)
		end

	process_export_item_as (l_as: EXPORT_ITEM_AS)
		do
			safe_process (l_as.clients)
			safe_process (l_as.features)
		end

	process_elseif_as (l_as: ELSIF_AS)
		do
			safe_process (l_as.elseif_keyword (match_list))
			safe_process (l_as.expr)
			safe_process (l_as.then_keyword (match_list))
			safe_process (l_as.compound)
		end

	process_elseif_expression_as (l_as: ELSIF_EXPRESSION_AS)
		do
			safe_process (l_as.elseif_keyword (match_list))
			l_as.condition.process (Current)
			safe_process (l_as.then_keyword (match_list))
			l_as.expression.process (Current)
		end

	process_create_as (l_as: CREATE_AS)
		do
			safe_process (l_as.create_creation_keyword (match_list))
			safe_process (l_as.clients)
			safe_process (l_as.feature_list)
		end

	process_client_as (l_as: CLIENT_AS)
		do
			safe_process (l_as.clients)
		end

	process_case_abstraction (a: CASE_ABSTRACTION_AS [detachable AST_EIFFEL])
			-- Process `a`.
		do
			safe_process (a.when_keyword (match_list))
			safe_process (a.interval)
			safe_process (a.then_keyword (match_list))
			safe_process (a.content)
		end

	process_case_as (a: CASE_AS)
		do
			process_case_abstraction (a)
		end

	process_case_expression_as (a: CASE_EXPRESSION_AS)
		do
			process_case_abstraction (a)
		end

	process_ensure_as (l_as: ENSURE_AS)
		do
			safe_process (l_as.ensure_keyword (match_list))
			safe_process (l_as.full_assertion_list)
		end

	process_ensure_then_as (l_as: ENSURE_THEN_AS)
		do
			safe_process (l_as.ensure_keyword (match_list))
			safe_process (l_as.then_keyword (match_list))
			safe_process (l_as.full_assertion_list)
		end

	process_require_as (l_as: REQUIRE_AS)
		do
			safe_process (l_as.require_keyword (match_list))
			safe_process (l_as.full_assertion_list)
		end

	process_require_else_as (l_as: REQUIRE_ELSE_AS)
		do
			safe_process (l_as.require_keyword (match_list))
			safe_process (l_as.else_keyword (match_list))
			safe_process (l_as.full_assertion_list)
		end

	process_convert_feat_as (l_as: CONVERT_FEAT_AS)
		do
			safe_process (l_as.feature_name)
			safe_process (l_as.colon_symbol (match_list))
			safe_process (l_as.lparan_symbol (match_list))
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.conversion_types)
			safe_process (l_as.rcurly_symbol (match_list))
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_type_list_as (l_as: TYPE_LIST_AS)
		do
			safe_process (l_as.opening_bracket_as (match_list))
			process_eiffel_list (l_as)
			safe_process (l_as.closing_bracket_as (match_list))
		end

	process_list_dec_list_as (l_as: LIST_DEC_LIST_AS)
		do
			safe_process (l_as.opening_bracket_as (match_list))
			process_eiffel_list (l_as)
			safe_process (l_as.closing_bracket_as (match_list))
		end

	process_type_dec_list_as (l_as: TYPE_DEC_LIST_AS)
		do
			safe_process (l_as.opening_bracket_as (match_list))
			process_eiffel_list (l_as)
			safe_process (l_as.closing_bracket_as (match_list))
		end

	process_convert_feat_list_as (l_as: CONVERT_FEAT_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.convert_keyword (match_list))
			process_eiffel_list (l_as)
		end

	process_class_list_as (l_as: CLASS_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.lcurly_symbol (match_list))
			process_eiffel_list (l_as)
			safe_process (l_as.rcurly_symbol (match_list))
		end

	process_parent_list_as (l_as: PARENT_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.inherit_keyword (match_list))
			safe_process (l_as.lcurly_symbol (match_list))
			safe_process (l_as.none_id_as (match_list))
			safe_process (l_as.rcurly_symbol (match_list))
			process_eiffel_list (l_as)
		end

	process_local_dec_list_as (l_as: LOCAL_DEC_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.local_keyword (match_list))
			safe_process(l_as.locals)
		end

	process_formal_argu_dec_list_as (l_as: FORMAL_ARGU_DEC_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.lparan_symbol (match_list))
			safe_process (l_as.arguments)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_key_list_as (l_as: KEY_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.lparan_symbol (match_list))
			safe_process (l_as.keys)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_delayed_actual_list_as (l_as: DELAYED_ACTUAL_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.lparan_symbol (match_list))
			safe_process (l_as.operands)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_parameter_list_as (l_as: PARAMETER_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.lparan_symbol (match_list))
			safe_process (l_as.parameters)
			safe_process (l_as.rparan_symbol (match_list))
		end

	process_named_expression_as (a_as: NAMED_EXPRESSION_AS)
			-- <Precursor>
		do
			a_as.expression.process (Current)
			safe_process (a_as.as_keyword (match_list))
			a_as.name.process (Current)
		end

	process_rename_clause_as (l_as: RENAME_CLAUSE_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.rename_keyword (match_list))
			safe_process (l_as.content)
		end

	process_export_clause_as (l_as: EXPORT_CLAUSE_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.export_keyword (match_list))
			safe_process (l_as.content)
		end

	process_undefine_clause_as (l_as: UNDEFINE_CLAUSE_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.undefine_keyword (match_list))
			safe_process (l_as.content)
		end

	process_redefine_clause_as (l_as: REDEFINE_CLAUSE_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.redefine_keyword (match_list))
			safe_process (l_as.content)
		end

	process_select_clause_as (l_as: SELECT_CLAUSE_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.select_keyword (match_list))
			safe_process (l_as.content)
		end

	process_formal_generic_list_as (l_as: FORMAL_GENERIC_LIST_AS)
			-- Process `l_as'.
		do
			safe_process (l_as.lsqure_symbol (match_list))
			process_eiffel_list (l_as)
			safe_process (l_as.rsqure_symbol (match_list))
		end

feature

	process_all_break_as
			-- Process all BREAK AST nodes in `match_list'.
		require
			match_list_not_void: match_list /= Void
			leading_leaves_not_processed: not will_process_leading_leaves
		local
			l_start_index, l_end_index, l_last_index: INTEGER
			l_index: INTEGER
		do
			l_start_index := start_index
			l_end_index := end_index
			l_last_index := last_index
			from
				l_index := 1
				start_index := 1
				last_index := 0
				end_index := match_list.count
			until
				l_index > end_index
			loop
				if attached {BREAK_AS} match_list.i_th (l_index) as l_break then
					l_break.process (Current)
				end
				l_index := l_index + 1
			end
			start_index := l_start_index
			end_index := l_end_index
			last_index := l_last_index
		end

feature{NONE} -- Implementation

	process_leading_leaves (ind: INTEGER)
			-- Process all not-processed leading leaves in `match_list' before index `ind'.
		require
			valid_index: ind >= start_index and then ind <= end_index
		local
			i: INTEGER
		do
			if
				will_process_leading_leaves and then
				ind > last_index + 1
			then
				from
					i := last_index + 1
				until
					i = ind
				loop
					match_list.i_th (i).process (Current)
					i := i + 1
				end
			end
		end

	process_trailing_leaves
			-- Process all trailing leaves in `match_list' after `last_index'.
		local
			l_count: INTEGER
		do
			if will_process_trailing_leaves then
				l_count := end_index
				if last_index < l_count then
					from
						last_index := last_index + 1
					until
						last_index > l_count
					loop
						match_list.i_th (last_index).process (Current)
						last_index := last_index + 1
					end
				end
			end
		end

	process_identifier_list (l_as: IDENTIFIER_LIST)
			-- Process `l_as'
		local
			i, l_count: INTEGER
			l_index: INTEGER
			l_id_as: ID_AS
			l_leaf: LEAF_AS
		do
			if
				attached l_as and then
				attached l_as.id_list as l_ids and then
				l_ids.count > 0
			then
				across
					l_ids as id_as_index
				from
					i := 1
						-- Temporary/reused objects to print identifiers.
					create l_id_as.initialize_from_id (1)
					if attached l_as.separator_list as l_sep_list then
						l_count := l_sep_list.count
					end
				loop
					l_index := id_as_index
					if match_list.valid_index (l_index) then
						l_leaf := match_list.i_th (l_index)
							-- Note that we do not set the `name_id' for `l_id_as' since it will require
							-- updating the NAMES_HEAP and we do not want to do that. It is assumed in roundtrip
							-- mode that the text is never obtained from the node itself but from the `text' queries.
						l_id_as.set_position (l_leaf.line, l_leaf.column, l_leaf.position, l_leaf.location_count,
							l_leaf.character_column, l_leaf.character_position, l_leaf.character_count)
						l_id_as.set_index (l_index)
						safe_process (l_id_as)
					end
					if i <= l_count then
						safe_process (l_as.separator_list_i_th (i, match_list))
						i := i + 1
					end
				end
			end
		end

	internal_match_list: detachable like match_list
			-- Storage for `match_list'.

;note
	ca_ignore: "CA033", "CA033: too large class"
	date: "$Date$"
	revision: "$Revision$"
	copyright: "Copyright (c) 1984-2023, Eiffel Software"
	license:   "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
	licensing_options: "http://www.eiffel.com/licensing"
	copying: "[
			This file is part of Eiffel Software's Eiffel Development Environment.
			
			Eiffel Software's Eiffel Development Environment is free
			software; you can redistribute it and/or modify it under
			the terms of the GNU General Public License as published
			by the Free Software Foundation, version 2 of the License
			(available at the URL listed under "license" above).
			
			Eiffel Software's Eiffel Development Environment is
			distributed in the hope that it will be useful, but
			WITHOUT ANY WARRANTY; without even the implied warranty
			of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
			See the GNU General Public License for more details.
			
			You should have received a copy of the GNU General Public
			License along with Eiffel Software's Eiffel Development
			Environment; if not, write to the Free Software Foundation,
			Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
		]"
	source: "[
			Eiffel Software
			5949 Hollister Ave., Goleta, CA 93117 USA
			Telephone 805-685-1006, Fax 805-685-6869
			Website http://www.eiffel.com
			Customer support http://support.eiffel.com
		]"

end