X-Git-Url: http://nitlanguage.org diff --git a/src/mmloader.nit b/src/mmloader.nit index ad35e01..c59b30c 100644 --- a/src/mmloader.nit +++ b/src/mmloader.nit @@ -2,6 +2,7 @@ # # Copyright 2006-2008 Floréal Morandat # Copyright 2008 Jean Privat +# Copyright 2009 Jean-Sebastien Gelinas # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,101 +16,67 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This package is used to load a metamodel +# This module is used to load a metamodel package mmloader import metamodel import opts +import toolcontext -# Global context for tools -class ToolContext -special MMContext - # Number of errors - readable attr _error_count: Int = 0 - - # Number of warnings - readable attr _warning_count: Int = 0 - - # Display an error - meth error(s: String) - do - stderr.write("{s}\n") - _error_count = _error_count + 1 - end - - # Display a warning - meth warning(s: String) - do - if not _opt_warn.value then return - stderr.write("{s}\n") - _warning_count = _warning_count + 1 - end +redef class ToolContext + super MMContext # Paths where to locate modules files - readable attr _paths: Array[String] + readable var _paths: Array[String] = new Array[String] # List of module loaders - attr _loaders: Array[ModuleLoader] = new Array[ModuleLoader] - - # Global OptionContext - readable attr _option_context: OptionContext = new OptionContext - - # Option --warn - readable attr _opt_warn: OptionBool = new OptionBool("Show warnings", "-W", "--warn") + var _loaders: Array[ModuleLoader] = new Array[ModuleLoader] # Option --path - readable attr _opt_path: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path") + readable var _opt_path: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path") - # Option --lop - readable attr _opt_log: OptionBool = new OptionBool("Generate various log files", "--log") - # Option --only-metamodel - readable attr _opt_only_metamodel: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel") + readable var _opt_only_metamodel: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel") # Option --only-parse - readable attr _opt_only_parse: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse") + readable var _opt_only_parse: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse") - # Option --help - readable attr _opt_help: OptionBool = new OptionBool("Show Help (This screen)", "-h", "-?", "--help") - - init + redef init do super - option_context.add_option(opt_warn, opt_path, opt_log, opt_only_parse, opt_only_metamodel, opt_help) + option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel) end # Parse and process the options given on the command line - meth process_options + redef fun process_options do - # init options - option_context.parse(args) + super # Setup the paths value - _paths = new Array[String] paths.append(opt_path.value) - var path_env = once ("NIT_PATH".to_symbol).environ - if not path_env.is_empty then + var path_env = "NIT_PATH".environ + if not path_env.is_empty then paths.append(path_env.split_with(':')) end - path_env = once ("NIT_DIR".to_symbol).environ - if not path_env.is_empty then + path_env = "NIT_DIR".environ + if not path_env.is_empty then var libname = "{path_env}/lib" if libname.file_exists then paths.add(libname) end var libname = "{sys.program_name.dirname}/../lib" - if libname.file_exists then paths.add(libname) + if libname.file_exists then paths.add(libname.simplify_path) end # Load and process a module in a directory (or a parent directory). # If the module is already loaded, just return it without further processing. # If no module is found, just return null without complaining. - private meth try_to_load(module_name: Symbol, dir: MMDirectory): MMModule + private fun try_to_load(module_name: Symbol, dir: MMDirectory): nullable MMModule do # Look in the module directory - for m in dir.modules do + for m in dir.modules.values do if m.name == module_name then return m end @@ -130,9 +97,7 @@ special MMContext var full_name = dir.full_name_for(module_name) if _processing_modules.has(full_name) then # FIXME: Generate better error - error("Error: Dependency loop for module {full_name}") - exit(1) - abort + fatal_error(null, "Error: Dependency loop for module {full_name}") end _processing_modules.add(full_name) var m = l.load_and_process_module(self, module_name, dir) @@ -147,12 +112,12 @@ special MMContext # List of module currently processed. # Used to prevent dependence loops. - attr _processing_modules: HashSet[Symbol] = new HashSet[Symbol] + var _processing_modules: HashSet[Symbol] = new HashSet[Symbol] # Locate, load and analysis a module (and its supermodules) from its file name. # If the module is already loaded, just return it without further processing. # Beware, the files are automatically considered root of their directory. - meth get_module_from_filename(filename: String): MMModule + fun get_module_from_filename(filename: String): MMModule do var path = filename.dirname var module_name = filename.basename(".nit").to_symbol @@ -170,8 +135,7 @@ special MMContext end if not filename.file_exists then - error("Error: File {filename} not found.") - exit(1) + fatal_error(null, "Error: File {filename} not found.") abort end @@ -179,18 +143,16 @@ special MMContext var m = try_to_load(module_name, dir) if m != null then return m - error("Error: {filename} is not a NIT source module.") - exit(1) + fatal_error(null, "Error: {filename} is not a NIT source module.") abort end # Locate, load and analysis a module (and its supermodules). # If the module is already loaded, just return it without further processing. - meth get_module(module_name: Symbol, from: MMModule): MMModule + fun get_module(module_name: Symbol, from: nullable MMModule): MMModule do - var m: MMModule if from != null then - var dir = from.directory + var dir: nullable MMDirectory = from.directory while dir != null do var m = try_to_load(module_name, dir) if m != null then return m @@ -203,13 +165,12 @@ special MMContext if m != null then return m end # FIXME: Generate better error - error("Error: No ressource found for module {module_name}.") - exit(1) + fatal_error(null, "Error: No ressource found for module {module_name}.") abort end # Return the module directory associated with a given path - private meth directory_for(path: String): MMDirectory + private fun directory_for(path: String): MMDirectory do if _path_dirs.has_key(path) then return _path_dirs[path] var dir = new MMDirectory(path.to_symbol, path, null) @@ -218,24 +179,24 @@ special MMContext end # Association bwtween plain path and module directories - attr _path_dirs: Map[String, MMDirectory] = new HashMap[String, MMDirectory] + var _path_dirs: Map[String, MMDirectory] = new HashMap[String, MMDirectory] # Register a new module loader - meth register_loader(ml: ModuleLoader) do _loaders.add(ml) + fun register_loader(ml: ModuleLoader) do _loaders.add(ml) end # A load handler know how to load a specific module type -class ModuleLoader +interface ModuleLoader # Type of module loaded by the loader type MODULE: MMModule # Extension that the loadhandler accepts - meth file_type: String is abstract + fun file_type: String is abstract # Try to load a new module directory - meth try_to_load_dir(dirname: Symbol, parent_dir: MMDirectory): MMDirectory + fun try_to_load_dir(dirname: Symbol, parent_dir: MMDirectory): nullable MMDirectory do - var fname = "{parent_dir.path}/{dirname}/" + var fname = "{parent_dir.path}/{dirname}" if not fname.file_exists then return null var dir = new MMDirectory(parent_dir.full_name_for(dirname), fname, parent_dir) @@ -244,7 +205,7 @@ class ModuleLoader # Can the loadhandler load a given module? # Return the file found - meth can_handle(module_name: Symbol, dir: MMDirectory): Bool + fun can_handle(module_name: Symbol, dir: MMDirectory): Bool do var fname = "{dir.path}/{module_name}.{file_type}" if fname.file_exists then return true @@ -253,16 +214,16 @@ class ModuleLoader # Load the module and process it # filename is the result of can_handle - meth load_and_process_module(context: ToolContext, module_name: Symbol, dir: MMDirectory): MODULE + fun load_and_process_module(context: ToolContext, module_name: Symbol, dir: MMDirectory): MODULE do - var filename = "{dir.path}/{module_name}.{file_type}" + var filename = "{dir.path}/{module_name}.{file_type}".simplify_path var m = load_module(context, module_name, dir, filename) if not context.opt_only_parse.value then process_metamodel(context, m) return m end # Load an parse the module - private meth load_module(context: ToolContext, module_name: Symbol, dir: MMDirectory, filename: String): MODULE + private fun load_module(context: ToolContext, module_name: Symbol, dir: MMDirectory, filename: String): MODULE do var file: IFStream if filename == "-" then @@ -272,9 +233,7 @@ class ModuleLoader end if file.eof then - context.error("Error: Problem in opening file {filename}") - exit(1) - abort + context.fatal_error(null, "Error: Problem in opening file {filename}") end var m = parse_file(context, file, filename, module_name, dir) if file != stdin then file.close @@ -282,23 +241,8 @@ class ModuleLoader end # Parse the file to load a module - protected meth parse_file(context: ToolContext, file: IFStream, filename: String, module_name: Symbol, dir: MMDirectory): MODULE is abstract + protected fun parse_file(context: ToolContext, file: IFStream, filename: String, module_name: Symbol, dir: MMDirectory): MODULE is abstract # Process a parsed module - protected meth process_metamodel(context: ToolContext, module: MODULE) is abstract -end - -redef class MMModule - # Recurcivelty process an import modules - meth import_supers_modules(names: Collection[Symbol]) - do - var c = context - assert c isa ToolContext - var supers = new Array[MMModule] - for n in names do - var m = c.get_module(n, self) - supers.add(m) - end - c.add_module(self,supers) - end + protected fun process_metamodel(context: ToolContext, mod: MODULE) is abstract end