note description: "Command that reads the description file generated by % % EiffelBench and fill the corresponding structures." legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" id: "$Id$" revision: "$Revision$" class IMPORT_APPLICATION_CLASS_CMD --| FIXME Extracted from Build. --| Not much changed except some bug fixes in the --| algorithms. inherit EB_ENVIRONMENT SHARED_CLASS_IMPORTER feature execute (arg: ANY) -- Read the description file and fill the internal structure. local directory: DIRECTORY description_file: PLAIN_TEXT_FILE description_name: PATH line: STRING dot_index: INTEGER do create directory.make_open_read (Common_directory) from directory.start directory.readentry until directory.lastentry = Void loop dot_index := directory.lastentry.index_of ('.', 1) line := directory.lastentry.substring (dot_index, directory.lastentry.count) if line.is_equal (".bui") then create description_name.make_from_string (Common_directory) description_name := description_name.extended (directory.lastentry) create description_file.make_with_name (description_name) if description_file.exists then description_file.open_read from description_file.start current_line := 0 until description_file.end_of_file loop current_line := 1 + current_line description_file.read_line line := clone (description_file.last_string) process_line (line) end description_file.close if current_application_class /= Void then update_routine_list update_query_list end end end directory.readentry end end feature {NONE} -- Implementation get_class_name, get_feature, get_precondition: BOOLEAN process_line (a_line: STRING) -- Add a command or a query, or create a new application class -- object according to the value of the line. local i: INTEGER do if not a_line.is_empty and a_line.count > 1 then a_line.left_adjust if a_line.substring_index (comment_keyword, 1) /= 1 and then a_line.substring_index (infix_keyword, 1) < 1 then --| not a comment line or an infix a_line.right_adjust if a_line.item(1).is_equal ('#') then if a_line.substring_index (classname_keyword, 1) > 0 then get_class_name := True elseif a_line.substring_index (feature_keyword, 1) > 0 then get_feature := True get_precondition := False elseif a_line.substring_index (precondition_keyword, 1) > 0 then get_precondition := True elseif a_line.substring_index (postcondition_keyword, 1) > 0 then get_precondition := False end elseif get_class_name then process_class_name (a_line) get_class_name := False elseif get_feature then if not a_line.has (':') then process_routine (a_line) elseif a_line.has ('(') and then a_line.has (')') then i := a_line.index_of (')', 1) if i = a_line.count then --| not a fonction if a_line.has (',') or else a_line.has (';') then process_routine (a_line) else process_command (a_line) end end else if a_line.substring_index (" is ", 1) < 1 then --| not a constant process_query (a_line) end end get_feature := False elseif get_precondition then process_precondition (a_line) end end end end process_class_name (class_name: STRING) -- Create a new application class object and add into the list. local an_app_class: APPLICATION_CLASS cmd_list: LINKED_LIST [APPLICATION_COMMAND] app_routine: APPLICATION_ROUTINE do if class_name.has (':') or class_name.has ('(') or class_name.has (')') then display_error_message else if not class_list.is_empty and then current_application_class /= Void then cmd_list := current_application_class.command_list from cmd_list.start until cmd_list.after loop create app_routine.make_from_command (cmd_list.item) current_application_class.add_routine (app_routine) cmd_list.forth end end create an_app_class.make (class_name) class_list.extend (an_app_class) class_list.finish end end process_command (signature: STRING) -- Add a command to the currently edited APPLICATION_CLASS object. local an_app_command: APPLICATION_COMMAND lower, upper: INTEGER cmd_name, arg_name, arg_type: STRING do signature.prune_all (' ') lower := 1 upper := signature.index_of ('(', 1) if (upper <= 1) or (upper > (signature.count - 5)) then display_error_message else cmd_name := signature.substring (lower, upper - 1) lower := upper + 1 upper := signature.index_of (':', lower) if (upper < lower) or (upper > (signature.count - 2)) then display_error_message else arg_name := signature.substring (lower, upper - 1) lower := upper + 1 upper := signature.index_of (')', lower) if (upper < lower) or (upper /= signature.count) then display_error_message else arg_type := signature.substring (lower, upper - 1) create an_app_command.make (cmd_name, arg_name, arg_type) current_application_class.add_command (an_app_command) current_application_method := an_app_command end end end end process_query (declaration: STRING) -- Add a query to the currently edited APPLICATION_CLASS object. local an_app_query: APPLICATION_QUERY i: INTEGER q_name, q_type: STRING do declaration.prune_all (' ') i := declaration.index_of (':', 1) if (i <= 1) or (i > (declaration.count - 2)) then display_error_message else q_name := declaration.substring (1, i - 1) q_type := declaration.substring (i + 1, declaration.count) if q_type.has ('(') or q_type.has (')') or q_type.has (':') or q_type.has (';') then display_error_message else create an_app_query.make (q_name, q_type) current_application_class.add_query (an_app_query) end end end process_routine (signature: STRING) -- Add a routine to currently edited APPLICATION_CLASS object. local app_routine: APPLICATION_ROUTINE lower, upper: INTEGER arg_lower, arg_upper: INTEGER cmd_name, arg_type, arg_name: STRING arg_list: LINKED_LIST [APPLICATION_ARGUMENT] arg: APPLICATION_ARGUMENT finished, error: BOOLEAN do signature.prune_all (' ') lower := 1 upper := signature.index_of ('(', 1) if (upper <= 1) then upper := signature.index_of (')', 1) if upper >= 1 then display_error_message else cmd_name := signature.substring (lower, signature.count) cmd_name.prune_all (' ') create arg_list.make end else cmd_name := signature.substring (lower, upper - 1) create arg_list.make from until finished or error loop lower := upper + 1 upper := signature.index_of (':', lower) if (upper <= 1) or (upper > (signature.count - 2)) then display_error_message error := True else arg_name := signature.substring (lower, upper - 1) lower := upper + 1 upper := signature.index_of (';', lower) if upper <= 1 then upper := signature.index_of (')', lower) if lower < upper then finished := True else display_error_message error := True end end if not finished then if upper <= 1 then display_error_message error := True else arg_type := signature.substring (lower, upper - 1) from until arg_upper > arg_name.count loop arg_lower := arg_upper + 1 arg_upper := arg_name.index_of (',', arg_lower) if arg_upper < 1 then arg_upper := arg_name.count + 1 end create arg.make (arg_name.substring (arg_lower, arg_upper - 1), arg_type) arg_list.extend (arg) end end end end end end if not error then create app_routine.make (cmd_name, arg_list) current_application_class.add_routine (app_routine) current_application_method := app_routine end end process_precondition (expression: STRING) -- Add a precondition to the currently edited APPLICATION_ROUTINE object. local a_precondition: APPLICATION_PRECONDITION lower, upper, semi_column_index: INTEGER do if current_application_method /= Void then from until upper >= expression.count loop lower := upper + 1 upper := expression.index_of (';', lower) if upper <= 1 then upper := expression.count + 1 end semi_column_index := expression.index_of (':', lower) if semi_column_index > 0 and then semi_column_index < upper then lower := semi_column_index + 2 end create a_precondition.make (expression.substring (lower, upper - 1)) current_application_method.add_precondition (a_precondition) end end end display_error_message -- Display Error message. do io.put_string ("Error in generated code at line") io.put_integer (current_line) io.new_line end update_routine_list -- Update routine list of `current_application_class' with -- command list at the end of file. local cmd_list: LINKED_LIST [APPLICATION_COMMAND] app_routine: APPLICATION_ROUTINE do cmd_list := current_application_class.command_list from cmd_list.start until cmd_list.after loop create app_routine.make_from_command (cmd_list.item) current_application_class.add_routine (app_routine) cmd_list.forth end end update_query_list -- Update routine list of `current_application_class' with -- command list at the end of file. local query_list: LINKED_LIST [APPLICATION_QUERY] do query_list := current_application_class.query_list from query_list.start until query_list.after loop query_list.item.sort_possible_methods (current_application_class) if query_list.item.possible_commands.is_empty and then query_list.item.possible_routines.is_empty then query_list.remove else query_list.forth end end end feature {NONE} -- Attributes current_line: INTEGER -- Current line current_application_method: APPLICATION_METHOD -- Currently edited application method object current_application_class: APPLICATION_CLASS -- Currently edited application class object do Result := class_list.item end feature {NONE} -- Constants classname_keyword: STRING = "#class#" -- Keyword "class" comment_keyword: STRING = "--" -- Keyword "--" feature_keyword: STRING = "#feature#" -- Keyword "feature" infix_keyword: STRING = "#infix#" -- Keyword "infix" precondition_keyword: STRING = "#require#" -- Keyword "require" postcondition_keyword: STRING = "#ensure#"; -- Keyword "ensure" note copyright: "Copyright (c) 1984-2006, 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 356 Storke Road, Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class IMPORT_APPLICATION_CLASS_CMD