1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Phases of the processing of nit programs
22 redef class ToolContext
23 # The various registered phases to performs
24 # The order in the poset is the dependence of phases
26 # While you can directly modify the poset (nodes and edges),
27 # it is often simpler to use the constructor in `Phase`
28 var phases
= new POSet[Phase]
31 var opt_disable_phase
= new OptionArray("Disable a specific phase; use `list` to get the list (debug)", "--disable-phase")
34 var opt_sloppy
= new OptionBool("Force lazy semantic analysis of the source-code (debug)", "--sloppy")
40 option_context
.add_option
(opt_disable_phase
, opt_sloppy
)
43 redef fun process_options
(args
)
47 for v
in opt_disable_phase
.value
do
49 for p
in phases_list
do
50 var deps
= p
.in_hierarchy
.direct_greaters
54 print
"{p} (dep: {deps.join(", ")})"
62 if v
!= p
.to_s
then continue
66 if not found
then fatal_error
(null, "Error: no phase named `{v}`. Use `list` to list all phases.")
69 if opt_sloppy
.value
then semantize_is_lazy
= true
72 # The list of registered phases in the application order.
73 var phases_list
: Sequence[Phase] is lazy
do
74 var phases
= self.phases
.to_a
75 self.phases
.sort
(phases
)
79 # Is `phase_process_npropdef` not called automatically by `run_phases`?
81 # When set to true, it is the responsibility of the tools
83 # Is false by default.
84 var semantize_is_lazy
= false is writable
86 # Set of already analyzed modules.
87 private var phased_modules
= new HashSet[AModule]
89 # List of module to process according to `run_phases`
91 # This allow some new modules to be found and added while analysing the code.
92 var todo_nmodules
: Sequence[AModule]
94 # Run all registered phases on a set of modules
95 fun run_phases
(nmodules
: Collection[AModule])
98 self.info
("*** SEMANTIC ANALYSIS ***", 1)
101 var phases
= phases_list
103 for phase
in phases
do
104 self.info
(" registered phases: {phase}", 2)
107 var todo_nmodules
= nmodules
.to_a
108 self.todo_nmodules
= todo_nmodules
110 while not todo_nmodules
.is_empty
do
111 var nmodule
= todo_nmodules
.shift
112 if phased_modules
.has
(nmodule
) then continue
113 phased_modules
.add nmodule
115 self.info
("Semantic analysis module {nmodule.location.file.filename}", 2)
117 var vannot
= new AnnotationPhaseVisitor
118 vannot
.enter_visit
(nmodule
)
120 for phase
in phases
do
121 if phase
.disabled
then continue
122 assert phase
.toolcontext
== self
123 var errcount
= self.error_count
124 phase
.process_nmodule
(nmodule
)
125 if errcount
!= self.error_count
then
128 errcount
= self.error_count
129 for nclassdef
in nmodule
.n_classdefs
do
130 assert phase
.toolcontext
== self
131 phase
.process_nclassdef
(nclassdef
)
132 if not semantize_is_lazy
then for npropdef
in nclassdef
.n_propdefs
do
133 assert phase
.toolcontext
== self
134 phase_process_npropdef
(phase
, npropdef
)
137 if errcount
!= self.error_count
then
140 for na
in vannot
.annotations
do
142 if p
isa AAnnotations then p
= p
.parent
144 phase
.process_annotated_node
(p
, na
)
146 if errcount
!= self.error_count
then
149 phase
.process_nmodule_after
(nmodule
)
155 self.info
("*** END SEMANTIC ANALYSIS: {time1-time0} ***", 2)
160 # Process the given `phase` on the `npropdef`
161 # Called by `run_phases`
162 protected fun phase_process_npropdef
(phase
: Phase, npropdef
: APropdef)
164 phase
.process_npropdef
(npropdef
)
167 # Run the phase on the given npropdef.
168 # Does nothing if `semantize_is_lazy` is false.
169 fun run_phases_on_npropdef
(npropdef
: APropdef)
171 if not semantize_is_lazy
then return
172 if npropdef
.is_phased
then return
173 npropdef
.is_phased
= true
175 #self.info("Semantic analysis of property {npropdef.location.file.filename}", 0)
177 var phases
= phases_list
178 for phase
in phases
do
179 if phase
.disabled
then continue
180 assert phase
.toolcontext
== self
181 phase_process_npropdef
(phase
, npropdef
)
188 # Is the propdef already analyzed by `run_phases_on_npropdef`.
189 # Unused unless `semantize_is_lazy` is true.
190 private var is_phased
= false
193 # Collect all annotation
194 private class AnnotationPhaseVisitor
197 # The collected annotations
198 var annotations
= new Array[AAnnotation]
203 if n
isa AAnnotation then annotations
.add n
207 # Abstraction of steps in the analysis/processing of Nit programs
208 # Specific phases should implements one of the `process_*` method
210 # The toolcontext instance attached to the phase
211 var toolcontext
: ToolContext
213 # The dependence relation of the phase with the other phases
214 var in_hierarchy
: POSetElement[Phase] is noinit
216 # The explicit dependences, used to initialize `in_importation`
217 var depends
: nullable Collection[Phase]
219 # Initialize and register a phase to the toolcontext
222 in_hierarchy
= toolcontext
.phases
.add_node
(self)
223 var depends
= self.depends
224 if depends
!= null then
226 toolcontext
.phases
.add_edge
(self, d
)
231 # By default, the name is the lowercased prefix of the classname
232 redef fun to_s
do return class_name
.strip_extension
("Phase").to_snake_case
234 # Is the phase globally disabled?
235 # A disabled phase is not called automatically called by `ToolContext::run_phases` and cie.
237 # Warning: disabling a phase may cause subsequent phases to work in a degraded way or to fail.
238 var disabled
= false is writable
240 # Specific actions to execute on the whole tree of a module
242 fun process_nmodule
(nmodule
: AModule) do end
244 # Specific actions to execute on the tree of a class definition
245 # Note that the order of the visit is the one of the file
247 fun process_nclassdef
(nclassdef
: AClassdef) do end
249 # Specific actions to execute on the tree of a property
250 # Note that the order of the visit is the one of the file
252 fun process_npropdef
(npropdef
: APropdef) do end
254 # Specific actions to execute on annotated nodes
255 # Note that the order of the visit is the one of the file
257 fun process_annotated_node
(node
: ANode, nat
: AAnnotation) do end
259 # Specific actions to execute on the whole tree of a module
260 # Called at the end of a phase on a module
263 fun process_nmodule_after
(nmodule
: AModule) do end