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