1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2006-2008 Floréal Morandat <morandat@lirmm.fr>
4 # Copyright 2008 Jean Privat <jean@pryen.org>
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
18 # This package is used to load a metamodel
24 # Global context for tools
28 readable attr _error_count
: Int
31 readable attr _warning_count
: Int
37 _error_count
= _error_count
+ 1
41 meth warning
(s
: String)
43 if not _opt_warn
.value
then return
45 _warning_count
= _warning_count
+ 1
48 # Paths where to locate modules files
49 readable attr _paths
: Array[String]
51 # List of module loaders
52 attr _loaders
: Array[ModuleLoader] = new Array[ModuleLoader]
54 # Global OptionContext
55 readable attr _option_context
: OptionContext = new OptionContext
58 readable attr _opt_warn
: OptionBool = new OptionBool("Show warnings", "-W", "--warn")
61 readable attr _opt_path
: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
64 readable attr _opt_log
: OptionBool = new OptionBool("Generate various log files", "--log")
66 # Option --only-metamodel
67 readable attr _opt_only_metamodel
: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel")
70 readable attr _opt_only_parse
: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
73 readable attr _opt_help
: OptionBool = new OptionBool("Show Help (This screen)", "-h", "-?", "--help")
78 option_context
.add_option
(opt_warn
, opt_path
, opt_log
, opt_only_parse
, opt_only_metamodel
, opt_help
)
81 # Parse and process the options given on the command line
85 option_context
.parse
(args
)
87 # Setup the paths value
88 _paths
= new Array[String]
89 paths
.append
(opt_path
.value
)
91 var path_env
= once
("NIT_PATH".to_symbol
).environ
92 if not path_env
.is_empty
then
93 paths
.append
(path_env
.split_with
(':'))
96 path_env
= once
("NIT_DIR".to_symbol
).environ
97 if not path_env
.is_empty
then
98 var libname
= "{path_env}/lib"
99 if libname
.file_exists
then paths
.add
(libname
)
102 var libname
= "{sys.program_name.dirname}/../lib"
103 if libname
.file_exists
then paths
.add
(libname
)
106 # Load and process a module in a directory (or a parent directory).
107 # If the module is already loaded, just return it without further processing.
108 # If no module is found, just return null without complaining.
109 private meth try_to_load
(module_name
: Symbol, dir
: MMDirectory): MMModule
111 # Look in the module directory
112 for m
in dir
.modules
do
113 if m
.name
== module_name
then return m
116 # print "try to load {module_name} in {dir.name} {_loaders.length}"
119 var dir2
= l
.try_to_load_dir
(module_name
, dir
)
121 var m
= try_to_load
(module_name
, dir2
)
129 if l
.can_handle
(module_name
, dir
) then
130 var full_name
= dir
.full_name_for
(module_name
)
131 if _processing_modules
.has
(full_name
) then
132 # FIXME: Generate better error
133 error
("Error: Dependency loop for module {full_name}")
137 _processing_modules
.add
(full_name
)
138 var m
= l
.load_and_process_module
(self, module_name
, dir
)
139 _processing_modules
.remove
(full_name
)
140 #if m != null then print "loaded {m.name} in {m.directory.name} -> {m.full_name} ({m.full_name.object_id.to_hex})"
148 # List of module currently processed.
149 # Used to prevent dependence loops.
150 attr _processing_modules
: HashSet[Symbol] = new HashSet[Symbol]
152 # Locate, load and analysis a module (and its supermodules) from its file name.
153 # If the module is already loaded, just return it without further processing.
154 # Beware, the files are automatically considered root of their directory.
155 meth get_module_from_filename
(filename
: String): MMModule
157 var path
= filename
.dirname
158 var module_name
= filename
.basename
(".nit").to_symbol
160 var dir
= directory_for
(path
)
162 if module_name
.to_s
== filename
then
163 # It's just a modulename
164 # look for it in the path directory "."
165 var m
= try_to_load
(module_name
, dir
)
166 if m
!= null then return m
168 # Else look for it in the path
169 return get_module
(module_name
, null)
172 if not filename
.file_exists
then
173 error
("Error: File {filename} not found.")
178 # Try to load the module where mentionned
179 var m
= try_to_load
(module_name
, dir
)
180 if m
!= null then return m
182 error
("Error: {filename} is not a NIT source module.")
187 # Locate, load and analysis a module (and its supermodules).
188 # If the module is already loaded, just return it without further processing.
189 meth get_module
(module_name
: Symbol, from
: MMModule): MMModule
193 var dir
= from
.directory
195 var m
= try_to_load
(module_name
, dir
)
196 if m
!= null then return m
202 var m
= try_to_load
(module_name
, directory_for
(p
))
203 if m
!= null then return m
205 # FIXME: Generate better error
206 error
("Error: No ressource found for module {module_name}.")
211 # Return the module directory associated with a given path
212 private meth directory_for
(path
: String): MMDirectory
214 if _path_dirs
.has_key
(path
) then return _path_dirs
[path
]
215 var dir
= new MMDirectory(path
.to_symbol
, path
, null)
216 _path_dirs
[path
] = dir
220 # Association bwtween plain path and module directories
221 attr _path_dirs
: Map[String, MMDirectory] = new HashMap[String, MMDirectory]
223 # Register a new module loader
224 meth register_loader
(ml
: ModuleLoader) do _loaders
.add
(ml
)
227 # A load handler know how to load a specific module type
229 # Type of module loaded by the loader
230 type MODULE: MMModule
232 # Extension that the loadhandler accepts
233 meth file_type
: String is abstract
235 # Try to load a new module directory
236 meth try_to_load_dir
(dirname
: Symbol, parent_dir
: MMDirectory): MMDirectory
238 var fname
= "{parent_dir.path}/{dirname}/"
239 if not fname
.file_exists
then return null
241 var dir
= new MMDirectory(parent_dir
.full_name_for
(dirname
), fname
, parent_dir
)
245 # Can the loadhandler load a given module?
246 # Return the file found
247 meth can_handle
(module_name
: Symbol, dir
: MMDirectory): Bool
249 var fname
= "{dir.path}/{module_name}.{file_type}"
250 if fname
.file_exists
then return true
254 # Load the module and process it
255 # filename is the result of can_handle
256 meth load_and_process_module
(context
: ToolContext, module_name
: Symbol, dir
: MMDirectory): MODULE
258 var filename
= "{dir.path}/{module_name}.{file_type}"
259 var m
= load_module
(context
, module_name
, dir
, filename
)
260 if not context
.opt_only_parse
.value
then process_metamodel
(context
, m
)
264 # Load an parse the module
265 private meth load_module
(context
: ToolContext, module_name
: Symbol, dir
: MMDirectory, filename
: String): MODULE
268 if filename
== "-" then
271 file
= new IFStream.open
(filename
.to_s
)
275 context
.error
("Error: Problem in opening file {filename}")
279 var m
= parse_file
(context
, file
, filename
, module_name
, dir
)
280 m
.filename
= filename
281 if file
!= stdin
then file
.close
285 # Parse the file to load a module
286 protected meth parse_file
(context
: ToolContext, file
: IFStream, filename
: String, module_name
: Symbol, dir
: MMDirectory): MODULE is abstract
288 # Process a parsed module
289 protected meth process_metamodel
(context
: ToolContext, module: MODULE) is abstract
293 # The filename of the module
294 readable writable attr _filename
: String
296 # Last modification time
297 readable writable attr _mtime
: Int
299 # Recurcivelty process an import modules
300 meth import_supers_modules
(names
: Collection[Symbol])
303 assert c
isa ToolContext
304 var supers
= new Array[MMModule]
306 var m
= c
.get_module
(n
, self)
309 c
.add_module
(self,supers
)