note description: "[ A class visitor to create a client class. - Each client only has the processor setter as its creation routine, with one exception: Clients for expanded original classes additionally list the default create routine, because this is an Eiffel requirement. ]" legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" class SCOOP_SEPARATE_CLIENT_PRINTER inherit SCOOP_CLIENT_CONTEXT_AST_PRINTER redefine process_class_as, process_feature_clause_as, process_feature_as end INTERNAL_COMPILER_STRING_EXPORTER create make, make_with_default_context feature -- Access add_client_class -- Add a client class for the original class indicated in the workbench. local l_printer: AST_ROUNDTRIP_PRINTER_VISITOR l_context: ROUNDTRIP_STRING_LIST_CONTEXT l_output: STRING do create l_context.make create l_printer.make (l_context) l_printer.setup (class_as, match_list_server.item (class_as.class_id), True, True) l_printer.process_ast_node (class_as) l_output := l_context.string_representation process_class_as (class_as) end feature {NONE} -- Implementation process_class_as (l_as: CLASS_AS) -- Process `l_as', the AST class node. require else class_as_not_void: class_as /= Void class_c_not_void: class_c /= Void local s: STRING_AS l_parent_visitor: SCOOP_CLIENT_PARENT_VISITOR l_generics_visitor: SCOOP_GENERICS_VISITOR l_last_index: INTEGER l_derived_class_information: SCOOP_DERIVED_CLASS_INFORMATION do -- Create `derived_class_information' create l_derived_class_information.make set_derived_class_information(l_derived_class_information) -- inicial comments to indicate the automated class generation context.add_string ("-- This class has been generated by SCOOP2SCOOPLI") context.add_string ("%N-- It implements separate clients for objects based on class " + class_as.class_name.name + "%N%N") -- since we produce only override classes we skip the indexing part -- safe_process (l_as.internal_top_indexes) -- if l_as.internal_top_indexes /= Void then -- last_index := l_as.internal_top_indexes.last_token (match_list).index -- end 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.separate_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) -- process internal generics if l_as.internal_generics /= Void then process_leading_leaves (l_as.internal_generics.index) l_generics_visitor := scoop_visitor_factory.new_generics_visitor (context) l_generics_visitor.process_class_internal_generics (l_as.internal_generics, False, False) last_index := l_generics_visitor.get_last_index end safe_process (l_as.alias_keyword (match_list)) s ?= l_as.external_class_name safe_process (s) safe_process (l_as.obsolete_keyword (match_list)) safe_process (l_as.obsolete_message) -- process parents l_parent_visitor := scoop_visitor_factory.new_client_parent_visitor (context) l_parent_visitor.process_internal_conforming_parents(l_as.internal_conforming_parents) l_parent_visitor.process_internal_non_conforming_parents (l_as.internal_non_conforming_parents) if l_as.conforming_parents /= Void or l_as.non_conforming_parents /= Void then last_index := l_parent_visitor.get_last_index end context.add_string ("%N%N") --- Change the creation clause to only include the processor setter. if not l_as.is_deferred then context.add_string ("%N%Ncreate%N%T" + {SCOOP_SYSTEM_CONSTANTS}.scoop_library_processor_setter_name) if l_as.is_expanded then context.add_string (", ") context.add_string (system.any_class.compiled_class.default_create_feature.feature_name) end end if l_as.creators /= void then last_index := l_as.creators.last_token (match_list).index end -- Process the convertors. safe_process (l_as.convertors) -- process feature clauses l_last_index := last_index insert_conversion(l_as) -- Added by `damienm' 4.Nov 2009 add_proxy_feature(l_as) -- Added by `damienm' 3.Nov 2009 last_index := l_last_index safe_process (l_as.features) if attached {ROUNDTRIP_STRING_LIST_CONTEXT} context as ctxt then derived_class_information.set_wrapper_insertion_index(ctxt.cursor_to_current_position) end -- add infix prefix feature wrappers -- Remove this call with EiffelStudio 6.4 insert_infix_prefix_wrappers if l_as.internal_invariant /= Void then is_processing_assertions := True last_index := l_as.internal_invariant.invariant_keyword_index - 1 context.add_string ("%N%N") safe_process (l_as.internal_invariant) is_processing_assertions := False end -- Skip invariant. if l_as.internal_invariant /= Void then last_index := l_as.internal_invariant.last_token (match_list).index end -- Skip indexes. last_index := l_as.end_keyword.index - 1 -- process end keyword context.add_string ("%N%N") safe_process (l_as.end_keyword) end process_feature_clause_as (l_as: FEATURE_CLAUSE_AS) -- Process `l_as', the AST feature clause list. do last_index := l_as.first_token (match_list).index context.add_string ("%N%N") safe_process (l_as.feature_keyword) -- Remove all clients. if l_as.clients /= void then last_index := l_as.clients.last_token (match_list).index end safe_process (l_as.features) end process_feature_as (l_as: FEATURE_AS) -- Process `l_as', the AST feature node, invoke the `SCOOP_CLIENT_FEATURE_VISITOR'. local l_feature_visitor: SCOOP_CLIENT_FEATURE_VISITOR do process_leading_leaves (l_as.feature_names.index) -- Process the feature node with the feature visitor l_feature_visitor := scoop_visitor_factory.new_client_feature_visitor (context) l_feature_visitor.add_client_features(l_as) last_index := l_as.last_token (match_list).index end insert_infix_prefix_wrappers -- Insert the wrapper feature of `scoop_workbench_objects.proxy_infix_prefix_wrappers'. -- Remove this item with EiffelStudio 6.4 local i, nb: INTEGER l_wrapper_list: LINKED_LIST [STRING] do l_wrapper_list := scoop_workbench_objects.proxy_infix_prefix_wrappers if l_wrapper_list /= Void and then l_wrapper_list.count > 0 then -- add a feature clause context.add_string ("%N%Nfeature {NONE} -- Wrapper features for infix / prefix features") -- add the features from i := 1 nb := l_wrapper_list.count until i > nb loop context.add_string (l_wrapper_list.i_th (i)) i := i + 1 end end end insert_conversion(l_as: CLASS_AS) -- Insert conversion clause for `proxy_' -- in order to allow up/down casts between separate and non separate entities -- Added by `damienm' 4.Nov 2009 local l_parent_visitor: SCOOP_CLIENT_PARENT_VISITOR l_generics_visitor: SCOOP_GENERICS_VISITOR l_ancestors: LINKED_LIST[STRING] l_table: HASH_TABLE[STRING,STRING] do if l_as.convertors = Void or l_as.convertors.is_empty then context.add_string ("%N%Nconvert%N%N") else context.add_string (",") end l_parent_visitor := scoop_visitor_factory.new_client_parent_visitor (context) context.add_string ("%N%Tproxy_: {"+proxy_class_prefix+l_as.class_name.name.as_upper) -- safe_process (l_as.generics) if l_as.internal_generics /= Void then process_leading_leaves (l_as.internal_generics.index) l_generics_visitor := scoop_visitor_factory.new_generics_visitor (context) l_generics_visitor.process_class_internal_generics (l_as.internal_generics, False, True) last_index := l_generics_visitor.get_last_index end create l_table.make (0) l_ancestors := l_parent_visitor.ancestors_names_list (l_as, l_table) if l_ancestors /= Void and not l_ancestors.is_empty then from l_ancestors.start until l_ancestors.after loop context.add_string (", "+proxy_class_prefix) context.add_string (l_ancestors.item) -- l_parent_visitor.process_parent_names(l_ancestors.item) -- context.add_string (l_ancestors.item.type.class_name.name) l_ancestors.forth end end context.add_string (", SCOOP_SEPARATE__ANY, SCOOP_SEPARATE_PROXY}%N%N") end add_proxy_feature(l_as: CLASS_AS) -- Add feature `proxy_' -- Added by `damienm' 3.Nov 2009 local l_generics_visitor : SCOOP_GENERICS_VISITOR do context.add_string("%N%Nfeature%N%N") context.add_string ("%Tproxy_: "+proxy_class_prefix+l_as.class_name.name.as_upper) if l_as.internal_generics /= Void then process_leading_leaves (l_as.internal_generics.index) l_generics_visitor := scoop_visitor_factory.new_generics_visitor (context) l_generics_visitor.process_class_internal_generics (l_as.internal_generics, False, True) last_index := l_generics_visitor.get_last_index end context.add_string ("%N%T%Tdo%N") if not l_as.is_deferred then context.add_string ("%T%T%TResult := create {"+proxy_class_prefix+l_as.class_name.name.as_upper) if l_as.internal_generics /= Void then l_generics_visitor.process_class_internal_generics (l_as.internal_generics, True, True) last_index := l_generics_visitor.get_last_index end context.add_string ("}.set_processor_ (Current.processor_)%N%T%T%TResult.set_implementation_(Current)%N") else context.add_string ("%N%T%T%Tresult := void") end context.add_string ("%N%N%T%Tend") end invariant context_not_void: context /= Void note copyright: "Copyright (c) 1984-2010, Chair of Software Engineering" 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: "[ ETH Zurich Chair of Software Engineering Website http://se.inf.ethz.ch/ ]" end -- class SCOOP_SEPARATE_CLIENT_PRINTER