6cdd20e549d72b2496a07ee41337ee1d27962fe7
[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 m.full_name = "{ns}{ns_separator}{basename}"
65 end
66 end
67
68 redef fun declare_namespace(id: String, full_name: String) do
69 var m: Module
70
71 assert not full_name.is_empty else
72 sys.stderr.write "Inner mamespace declarations without name are not yet supported.\n"
73 end
74 if inner_namespaces.keys.has(full_name) then
75 m = inner_namespaces[full_name]
76 if id != "" then m.parent = id
77 else
78 m = new Module(graph)
79 m.full_name = "{full_name}{ns_separator}{basename}"
80 m.parent = id
81 m.location = self["location"].as(nullable Location)
82 inner_namespaces[full_name] = m
83 end
84 end
85
86 redef fun declare_class(id: String, full_name: String) do
87 assert not id.is_empty else
88 sys.stderr.write "Inner class declarations without ID are not yet supported.\n"
89 end
90 assert not full_name.is_empty else
91 sys.stderr.write "Inner class declarations without name are not yet supported.\n"
92 end
93 var match = full_name.search_last(ns_separator)
94 var ns_name: String
95 var m: Module
96
97 if match == null then
98 ns_name = ""
99 else
100 ns_name = full_name.substring(0, match.from)
101 end
102 if inner_namespaces.keys.has(ns_name) then
103 m = inner_namespaces[ns_name]
104 else
105 declare_namespace("", ns_name)
106 m = inner_namespaces[ns_name]
107 end
108 m.declare_class(id, full_name)
109 end
110
111 redef fun put_in_graph do
112 # Do not add `self` to the Neo4j graph...
113 # ... but add its modules...
114 for m in inner_namespaces.values do m.put_in_graph
115 # ... and add `self` to the index.
116 if model_id != "" then graph.by_id[model_id] = self
117 end
118 end
119
120 # A module.
121 class Module
122 super Compound
123 super CodeBlock
124
125 # The `model_id` of the parent namespace.
126 var parent: String = "" is writable
127
128 # The classes defined in the module.
129 var inner_classes: SimpleCollection[String] = new Array[String]
130
131 init do
132 super
133 self.labels.add("MModule")
134 end
135
136 redef fun declare_class(id: String, full_name: String) do
137 assert not id.is_empty else
138 sys.stderr.write "Inner class declarations without ID not supported yet.\n"
139 end
140 inner_classes.add(id)
141 end
142
143 redef fun put_edges do
144 graph.add_edge(graph.by_id[parent], "DECLARES", self)
145 for c in inner_classes do
146 var node = graph.by_id[c].as(ClassCompound)
147 graph.add_edge(self, "INTRODUCES", node)
148 graph.add_edge(self, "DEFINES", node.class_def)
149 end
150 end
151 end