neo_doxygen: Accept classes in the root namespace.
[nit.git] / contrib / neo_doxygen / src / model / graph.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 # Graphs and basic entities.
16 module model::graph
17
18 import neo4j
19 import location
20
21 # A Neo4j graph.
22 class NeoGraph
23 # All the nodes in the graph.
24 var all_nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
25
26 # All the edges in the graph.
27 var all_edges: SimpleCollection[NeoEdge] = new Array[NeoEdge]
28
29 # Add a relationship between two nodes.
30 #
31 # Parameters are the same than for the constructor of `NeoEdge`.
32 fun add_edge(from: NeoNode, rel_type: String, to: NeoNode) do
33 all_edges.add(new NeoEdge(from, rel_type, to))
34 end
35 end
36
37 # A project’s graph.
38 class ProjectGraph
39 super NeoGraph
40
41 # The project’s name.
42 var project_name: String
43
44 # The node reperesenting the project.
45 #
46 # Once the project’s graph is initialized, this node must not be edited.
47 var project = new NeoNode
48
49 # Entities by `model_id`.
50 var by_id: Map[String, Entity] = new HashMap[String, Entity]
51
52 # Initialize a new project graph using the specified project name.
53 #
54 # The specified name will label all nodes of the project’s graph.
55 init do
56 project.labels.add(project_name)
57 project.labels.add("MEntity")
58 project.labels.add("MProject")
59 project["name"] = project_name
60 all_nodes.add(project)
61
62 var root = new RootNamespace(self)
63 root.put_in_graph
64 by_id[""] = root
65 end
66
67 # Request to all nodes in the graph to add their related edges.
68 fun put_edges do
69 all_edges.clear
70 add_edge(project, "ROOT", by_id[""])
71 for n in all_nodes do
72 if n isa Entity then
73 n.put_edges
74 end
75 end
76 end
77 end
78
79 # A model’s entity.
80 #
81 # In practice, this is the base class of every node in a `ProjectGraph`.
82 abstract class Entity
83 super NeoNode
84
85 # Graph that will embed the entity.
86 var graph: ProjectGraph
87
88 # ID of the entity in the model.
89 #
90 # Is empty for entities without an ID.
91 var model_id: String = "" is writable
92
93 # Associated documentation.
94 var doc = new JsonArray is writable
95
96 init do
97 self.labels.add(graph.project_name)
98 self.labels.add("MEntity")
99 end
100
101 # The short (unqualified) name.
102 #
103 # May be also set by `full_name=`.
104 fun name=(name: String) do
105 self["name"] = name
106 end
107
108 # The short (unqualified) name.
109 fun name: String do
110 var name = self["name"]
111 assert name isa String
112 return name
113 end
114
115 # Include the documentation of `self` in the graph.
116 protected fun set_mdoc do
117 self["mdoc"] = doc
118 end
119
120 # The namespace separator of Nit/C++.
121 fun ns_separator: String do return "::"
122
123 # The name separator used when calling `full_name=`.
124 fun name_separator: String do return ns_separator
125
126 # The full (qualified) name.
127 #
128 # Also set `name` using `name_separator`.
129 fun full_name=(full_name: String) do
130 var m: nullable Match = full_name.search_last(name_separator)
131
132 self["full_name"] = full_name
133 if m == null then
134 name = full_name
135 else
136 name = full_name.substring_from(m.after)
137 end
138 end
139
140 # The full (qualified) name.
141 fun full_name: String do
142 var full_name = self["full_name"]
143 assert full_name isa String
144 return full_name
145 end
146
147 # Set the full name using the current name and the specified parent name.
148 fun parent_name=(parent_name: String) do
149 if parent_name.is_empty then
150 self["full_name"] = name
151 else
152 self["full_name"] = parent_name + name_separator + name
153 end
154 end
155
156 # Set the location of the entity in the source code.
157 fun location=(location: nullable Location) do
158 self["location"] = location
159 end
160
161 # Put the entity in the graph.
162 #
163 # Called by the loader when it has finished to read the entity.
164 fun put_in_graph do
165 if doc.length > 0 then
166 set_mdoc
167 end
168 graph.all_nodes.add(self)
169 if model_id != "" then graph.by_id[model_id] = self
170 end
171
172 # Put the related edges in the graph.
173 #
174 # This method is called on each node by `ProjectGraph.put_edges`.
175 #
176 # Note: Even at this step, the entity may modify its own attributes and
177 # inner entities’ ones because some values are only known once the entity
178 # know its relationships with the rest of the graph.
179 fun put_edges do end
180 end
181
182 # An entity whose the location is mandatory.
183 abstract class CodeBlock
184 super Entity
185
186 init do
187 self["location"] = new Location
188 end
189
190 redef fun location=(location: nullable Location) do
191 if location == null then
192 super(new Location)
193 else
194 super
195 end
196 end
197 end
198
199 # A compound.
200 #
201 # Usually corresponds to a `<compounddef>` element in of the XML output of
202 # Doxygen.
203 abstract class Compound
204 super Entity
205
206 # Set the declared visibility (the proctection) of the compound.
207 fun visibility=(visibility: String) do
208 self["visibility"] = visibility
209 end
210
211 # Set the specific kind of the compound.
212 fun kind=(kind: String) do
213 self["kind"] = kind
214 end
215
216 # Declare an inner namespace.
217 #
218 # Note: Althought Doxygen indicates that the name is optional,
219 # declarations with an empty name are not supported yet, except for the root
220 # namespace. For the root namespace, both arguments are empty.
221 #
222 # Parameters:
223 #
224 # * `id`: `model_id` of the inner namespace. May be empty.
225 # * `full_name`: qualified name of the inner namespace. Use an empty name
226 # for the root namespace.
227 fun declare_namespace(id: String, full_name: String) do end
228
229 # Declare an inner class.
230 #
231 # Note: Althought Doxygen indicates that both arguments are optional,
232 # declarations with either an empty name or an empty ID are not
233 # supported yet.
234 #
235 # Parameters:
236 #
237 # * `id`: `model_id` of the inner class.
238 # * `full_name`: qualified name of the inner class.
239 fun declare_class(id: String, full_name: String) do end
240
241 # Declare a base compound (usually, a base class).
242 #
243 # Parameters:
244 #
245 # * `id`: `model_id` of the base compound. May be empty.
246 # * `full_name`: qualified name of the base compound. May be empty.
247 # * `prot`: visibility (proctection) of the relationship.
248 # * `virt`: level of virtuality of the relationship.
249 fun declare_super(id: String, full_name: String, prot: String,
250 virt: String) do end
251 end
252
253 # An unrecognized compound.
254 #
255 # Used to simplify the handling of ignored entities.
256 class UnknownCompound
257 super Compound
258
259 redef fun put_in_graph do end
260 redef fun put_edges do end
261 end
262
263 # A namespace.
264 #
265 # Corresponds to a group in Nit.
266 class Namespace
267 super Compound
268
269 # Inner namespaces (IDs).
270 #
271 # Left empty for the root namespace.
272 var inner_namespaces: SimpleCollection[String] = new Array[String]
273
274 init do
275 super
276 self.labels.add("MGroup")
277 end
278
279 redef fun declare_namespace(id: String, name: String) do
280 inner_namespaces.add(id)
281 end
282
283 redef fun put_edges do
284 super
285 graph.add_edge(self, "PROJECT", graph.project)
286 if self["name"] == self["full_name"] and self["full_name"] != "" then
287 # The root namespace does not know its children.
288 var root = graph.by_id[""]
289 graph.add_edge(self, "PARENT", root)
290 graph.add_edge(root, "NESTS", self)
291 end
292 for ns in inner_namespaces do
293 var node = graph.by_id[ns]
294 graph.add_edge(node, "PARENT", self)
295 graph.add_edge(self, "NESTS", node)
296 end
297 end
298 end
299
300 # The root namespace of a `ProjectGraph`.
301 #
302 # This the only entity in the graph whose `model_id` is really `""`.
303 # Added automatically at the initialization of a `ProjectGraph`.
304 class RootNamespace
305 super Namespace
306
307 init do
308 super
309 self["full_name"] = ""
310 self["name"] = graph.project["name"]
311 end
312
313 redef fun declare_namespace(id: String, name: String) do end
314 end