945eb3157824bf0450e158bcdd51087fbdc0d4d7
[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.intro
122 end
123 visit_all(v)
124 end
125 end
126
127 redef class AStdImport
128 redef fun accept_example_visitor(v) do
129 var mmodule = self.mmodule
130 if mmodule != null then
131 v.counter.inc mmodule
132
133 var mgroup = mmodule.mgroup
134 if mgroup != null then
135 v.counter.inc mgroup
136 v.counter.inc mgroup.mpackage
137 end
138 end
139 end
140 end
141
142 redef class AStdClassdef
143 redef fun accept_example_visitor(v) do
144 var mclassdef = self.mclassdef
145 if mclassdef == null then return
146
147 if not mclassdef.is_intro then
148 v.counter.inc mclassdef.mclass.intro
149 end
150 visit_all(v)
151 end
152 end
153
154 redef class APropdef
155 redef fun accept_example_visitor(v) do
156 var mpropdef = self.mpropdef
157 if mpropdef == null then return
158
159 if not mpropdef.is_intro then
160 v.counter.inc mpropdef.mproperty.intro.mclassdef.mclass
161 v.counter.inc mpropdef.mproperty.intro.mclassdef
162 v.counter.inc mpropdef.mproperty.intro
163 end
164 visit_all(v)
165 end
166 end
167
168 redef class ASuperPropdef
169 redef fun accept_example_visitor(v) do
170 var mtype = self.n_type.mtype
171 if mtype isa MClassType then
172 v.counter.inc mtype.mclass
173 v.counter.inc mtype.mclass.intro
174 end
175 visit_all(v)
176 end
177 end
178
179 redef class ASendExpr
180 redef fun accept_example_visitor(v) do
181 var callsite = self.callsite
182 if callsite == null then return
183 v.counter.inc callsite.mpropdef
184 v.counter.inc callsite.mpropdef.mproperty
185 v.counter.inc callsite.mpropdef.mclassdef
186 v.counter.inc callsite.mpropdef.mclassdef.mclass
187 visit_all(v)
188 end
189 end