neo_doxygen: Accept classes in the root namespace.
[nit.git] / contrib / neo_doxygen / src / model / module_compound.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 # Nodes for modules and files.
16 module model::module_compound
17
18 import graph
19 import class_compound
20
21 # A source file.
22 #
23 # Creates one modules by inner namespace. The full name of the modules begin
24 # with the namespace’s full name, and end with the unqualified name of the file,
25 # without the extension.
26 class FileCompound
27 super Compound
28 super CodeBlock
29
30 # Mapping between inner namespace’s names and corresponding modules.
31 private var inner_namespaces: Map[String, Module] = new HashMap[String, Module]
32
33 # The last component of the path, without the extension.
34 #
35 # Used as the unqualified name of the modules.
36 private var basename: String = ""
37
38 init do
39 super
40 end
41
42 redef fun name_separator: String do return "/"
43
44 redef fun location=(location: nullable Location) do
45 super
46 if location != null and location.path != null then
47 full_name = location.path.as(not null)
48 end
49 for m in inner_namespaces.values do m.location = location
50 end
51
52 redef fun name=(name: String) do
53 # Example: `MyClass.java`
54 super
55 var match = name.search_last(".")
56
57 if match == null then
58 basename = name
59 else
60 basename = name.substring(0, match.from)
61 end
62 # Update the modules’ name.
63 for ns, m in inner_namespaces do
64 if ns.is_empty then
65 m.full_name = basename
66 else
67 m.full_name = "{ns}{ns_separator}{basename}"
68 end
69 end
70 end
71
72 redef fun declare_namespace(id: String, full_name: String) do
73 var m: Module
74
75 assert not full_name.is_empty or id.is_empty else
76 sys.stderr.write "Inner mamespace declarations without name are not yet supported (except for the root namespace).\n"
77 end
78 if inner_namespaces.keys.has(full_name) then
79 m = inner_namespaces[full_name]
80 if id != "" then m.parent = id
81 else
82 m = new Module(graph)
83 if full_name.is_empty then
84 m.full_name = basename
85 else
86 m.full_name = "{full_name}{ns_separator}{basename}"
87 end
88 m.parent = id
89 m.location = self["location"].as(nullable Location)
90 inner_namespaces[full_name] = m
91 end
92 end
93
94 redef fun declare_class(id: String, full_name: String) do
95 assert not id.is_empty else
96 sys.stderr.write "Inner class declarations without ID are not yet supported.\n"
97 end
98 assert not full_name.is_empty else
99 sys.stderr.write "Inner class declarations without name are not yet supported.\n"
100 end
101 var match = full_name.search_last(ns_separator)
102 var ns_name: String
103 var m: Module
104
105 if match == null then
106 ns_name = ""
107 else
108 ns_name = full_name.substring(0, match.from)
109 end
110 if inner_namespaces.keys.has(ns_name) then
111 m = inner_namespaces[ns_name]
112 else
113 declare_namespace("", ns_name)
114 m = inner_namespaces[ns_name]
115 end
116 m.declare_class(id, full_name)
117 end
118
119 redef fun put_in_graph do
120 # Do not add `self` to the Neo4j graph...
121 # ... but add its modules...
122 for m in inner_namespaces.values do m.put_in_graph
123 # ... and add `self` to the index.
124 if model_id != "" then graph.by_id[model_id] = self
125 end
126 end
127
128 # A module.
129 class Module
130 super Compound
131 super CodeBlock
132
133 # The `model_id` of the parent namespace.
134 var parent: String = "" is writable
135
136 # The classes defined in the module.
137 var inner_classes: SimpleCollection[String] = new Array[String]
138
139 init do
140 super
141 self.labels.add("MModule")
142 end
143
144 redef fun declare_class(id: String, full_name: String) do
145 assert not id.is_empty else
146 sys.stderr.write "Inner class declarations without ID not supported yet.\n"
147 end
148 inner_classes.add(id)
149 end
150
151 redef fun put_edges do
152 graph.add_edge(graph.by_id[parent], "DECLARES", self)
153 for c in inner_classes do
154 var node = graph.by_id[c].as(ClassCompound)
155 graph.add_edge(self, "INTRODUCES", node)
156 graph.add_edge(self, "DEFINES", node.class_def)
157 end
158 end
159 end