ni_nitdoc: added fast copy past utility to signatures.
[nit.git] / src / div_by_zero.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
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
17 module div_by_zero
18
19 import phase
20 import literal # Because we need the real value of literal in the AST
21 import typing # Because we need the static type of receivers
22
23 # Note, `ToolContext` is the main overlord class
24 # Among its jobs, it orchestrates and executes the various phases
25 redef class ToolContext
26 # Instantiate a new specific phase `div_by_zero_phase`
27 # It must be executed after the two phases `literal_phase` and `typing_phase`
28 # Those two phases are statically known since they are introduced by the modules `literal` and `typing`
29 # Note that the constructor automatically register the phase to the ToolContext; this explains why there is `self`
30 var div_by_zero_phase: Phase = new DivByZeroPhase(self, [literal_phase, typing_phase])
31 end
32
33 # OK, let we create a specific phase
34 private class DivByZeroPhase
35 super Phase
36
37 # Specific phases just have to implement the `process_nmodule` method.
38 redef fun process_nmodule(nmodule)
39 do
40 # The AST node is not enough, we need also the associated model element
41 var mmodule = nmodule.mmodule.as(not null)
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)
46 end
47 end
48
49 # The real visitor that does the real job
50 private class DivByZeroVisitor
51 super Visitor
52
53 # The toolcontext is our entree point to most services
54 var toolcontext: ToolContext
55
56 # The mmodule is the current module
57 var mmodule: MModule
58
59 init(toolcontext: ToolContext, mmodule: MModule)
60 do
61 self.toolcontext = toolcontext
62 self.mmodule = mmodule
63 end
64
65 redef fun visit(node)
66 do
67 # Recursively visit all sub-nodes
68 node.visit_all(self)
69
70 # Now just filter out until we get what we want...
71
72 # 1. We need a `/` operation
73 if not node isa ASlashExpr then return
74
75 # 2. The second operand must be a integer literal
76 var op2 = node.n_expr2
77 if not op2 isa AIntExpr then return
78
79 # 3. Its value must be 0
80 # Note: because of `literal_phase` the `value` method exists
81 if op2.value != 0 then return
82
83 # 4. The receiver (first operand) must be an Int
84 var op1 = node.n_expr
85 var int_type = mmodule.get_primitive_class("Int").mclass_type
86 if not op1.mtype.is_subtype(mmodule, null, int_type) then return
87
88 # Error detected
89 toolcontext.error(node.location, "Error: Definitely division by zero")
90 end
91 end