84c83a6121f3a46a4f3443507faf80bdc8d64240
[nit.git] / src / frontend / parse_examples.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 # Example parsing
16 #
17 # This module parses example from mentities annotated with `is example`.
18 #
19 # TODO rank examples
20 module parse_examples
21
22 import counter
23 import typing
24 import parse_annotations
25 import doc_down
26 import model::model_examples
27
28 redef class ToolContext
29
30 # Examples parsing phase
31 var examples_phase: Phase = new ExamplesPhase(self,
32 [typing_phase, parse_annotations_phase])
33 end
34
35 # Parse examples from modules, classdefs and propdefs
36 #
37 # For each node annotated with `is example` we parse the example and associate
38 # it with existing model entities.
39 #
40 # Association between examples and mentities is based on:
41 # `MModule`: Used in `import`
42 # `MClassDef`: Used in `super`, redefined class, init or other method called
43 # `MPropDef`: Used in `super`, redefined property, called
44 private class ExamplesPhase
45 super Phase
46
47 redef fun process_nmodule(nmodule) do
48 var mmodule = nmodule.mmodule
49 if mmodule == null then return
50
51 if not mmodule.has_annotation("example") then return
52
53 process_example(mmodule, nmodule)
54 end
55
56 redef fun process_nclassdef(nclassdef) do
57 var mclassdef = nclassdef.mclassdef
58 if mclassdef == null then return
59
60 if not mclassdef.has_annotation("example") and not mclassdef.mmodule.is_example then return
61
62 process_example(mclassdef, nclassdef)
63 end
64
65 redef fun process_npropdef(npropdef) do
66 var mpropdef = npropdef.mpropdef
67 if mpropdef == null then return
68
69 if not mpropdef.has_annotation("example") and not mpropdef.mclassdef.is_example then return
70
71 process_example(mpropdef, npropdef)
72 end
73
74 # Process an mentity as an MExample
75 #
76 # This method parses the mentity node and link the mentity to possible
77 # examplified entities.
78 fun process_example(example_mentity: MEntity, node: ANode) do
79 var visitor = new ExampleVisitor(toolcontext)
80 visitor.enter_visit(node)
81 var sorted = visitor.counter.sort.reversed
82
83 var example = new MExample(example_mentity)
84 example.node = node
85 for mentity in sorted do
86 example.example_for[mentity] = visitor.counter[mentity]
87 if not mentity.examples.has(example) then mentity.examples.add example
88 end
89 end
90 end
91
92 redef class MExample
93 # AST node containing the example code
94 var node: nullable ANode = null is writable
95 end
96
97 # Example parsing
98
99 # Visit examples to find what they are an example for.
100 private class ExampleVisitor
101 super Visitor
102
103 var counter = new Counter[MEntity]
104
105 # The toolcontext is our entree point to most services
106 var toolcontext: ToolContext
107
108 redef fun visit(node) do
109 node.accept_example_visitor(self)
110 end
111 end
112
113 redef class ANode
114 private fun accept_example_visitor(v: ExampleVisitor) do visit_all(v)
115 end
116
117 redef class ANewExpr
118 redef fun accept_example_visitor(v) do
119 var recvtype = self.recvtype
120 if recvtype != null then
121 v.counter.inc recvtype.mclass
122 v.counter.inc recvtype.mclass.intro
123 end
124 visit_all(v)
125 end
126 end
127
128 redef class AStdImport
129 redef fun accept_example_visitor(v) do
130 var mmodule = self.mmodule
131 if mmodule != null then
132 v.counter.inc mmodule
133
134 var mgroup = mmodule.mgroup
135 if mgroup != null then
136 v.counter.inc mgroup
137 v.counter.inc mgroup.mpackage
138 end
139 end
140 end
141 end
142
143 redef class AStdClassdef
144 redef fun accept_example_visitor(v) do
145 var mclassdef = self.mclassdef
146 if mclassdef == null then return
147
148 if not mclassdef.is_intro then
149 v.counter.inc mclassdef.mclass.intro
150 end
151 visit_all(v)
152 end
153 end
154
155 redef class APropdef
156 redef fun accept_example_visitor(v) do
157 var mpropdef = self.mpropdef
158 if mpropdef == null then return
159
160 if not mpropdef.is_intro then
161 v.counter.inc mpropdef.mproperty.intro.mclassdef.mclass
162 v.counter.inc mpropdef.mproperty.intro.mclassdef
163 v.counter.inc mpropdef.mproperty.intro
164 end
165 visit_all(v)
166 end
167 end
168
169 redef class ASuperPropdef
170 redef fun accept_example_visitor(v) do
171 var mtype = self.n_type.mtype
172 if mtype isa MClassType then
173 v.counter.inc mtype.mclass
174 v.counter.inc mtype.mclass.intro
175 end
176 visit_all(v)
177 end
178 end
179
180 redef class ASendExpr
181 redef fun accept_example_visitor(v) do
182 var callsite = self.callsite
183 if callsite == null then return
184 v.counter.inc callsite.mpropdef
185 v.counter.inc callsite.mpropdef.mproperty
186 v.counter.inc callsite.mpropdef.mclassdef
187 v.counter.inc callsite.mpropdef.mclassdef.mclass
188 visit_all(v)
189 end
190 end