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 # Detection of divisions by zero in obvious cases
16 # This module is only an example of how to implements a simple phase in the nit tools
19 import literal
# Because we need the real value of literal in the AST
20 import semantize
# Because we need the static type of receivers
22 # Note, `ToolContext` is the main overlord class
23 # Among its jobs, it orchestrates and executes the various phases
24 redef class ToolContext
25 # Instantiate a new specific phase `div_by_zero_phase`
26 # It must be executed after the two phases `literal_phase` and `typing_phase`
27 # Those two phases are statically known since they are introduced by the modules `literal` and `typing`
28 # Note that the constructor automatically register the phase to the ToolContext; this explains why there is `self`
29 var div_by_zero_phase
: Phase = new DivByZeroPhase(self, [literal_phase
, typing_phase
])
32 # OK, let we create a specific phase
33 private class DivByZeroPhase
36 # Specific phases just have to implement the `process_nmodule` method.
37 redef fun process_nmodule
(nmodule
)
39 # The AST node is not enough, we need also the associated model element
40 var mmodule
= nmodule
.mmodule
41 if mmodule
== null then return
42 # For the specific job we have, the simpler it to launch a visitor on
43 # all elements of the AST.
44 var visitor
= new DivByZeroVisitor(toolcontext
, mmodule
)
45 visitor
.enter_visit
(nmodule
)
49 # The real visitor that does the real job
50 private class DivByZeroVisitor
53 # The toolcontext is our entree point to most services
54 var toolcontext
: ToolContext
56 # The mmodule is the current module
61 # Recursively visit all sub-nodes
64 # Now just filter out until we get what we want...
66 # 1. We need a `/` operation
67 if not node
isa ASlashExpr then return
69 # 2. The second operand must be a integer literal
70 var op2
= node
.n_expr2
71 if not op2
isa AIntExpr then return
73 # 3. Its value must be 0
74 # Note: because of `literal_phase` the `value` method exists
75 if op2
.value
!= 0 then return
77 # 4. The receiver (first operand) must be an Int
79 var int_type
= mmodule
.get_primitive_class
("Int").mclass_type
80 if not op1
.mtype
.is_subtype
(mmodule
, null, int_type
) then return
83 toolcontext
.warning
(node
.location
, "div-by-zero", "Warning: division by zero.")