model: add mmodule_data
authorJean Privat <jean@pryen.org>
Thu, 31 Jul 2014 03:46:50 +0000 (23:46 -0400)
committerJean Privat <jean@pryen.org>
Thu, 31 Jul 2014 12:50:11 +0000 (08:50 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

src/model/mmodule_data.nit [new file with mode: 0644]

diff --git a/src/model/mmodule_data.nit b/src/model/mmodule_data.nit
new file mode 100644 (file)
index 0000000..ad4762e
--- /dev/null
@@ -0,0 +1,129 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Define and retrieve data in modules
+# This module help analysis and tool to store piece of data in `MModule` then
+# retrieve them through the importation relation.
+module mmodule_data
+
+import mmodule
+
+# A map-like structure to associate `E` to` MModule`
+# The advantage of this class is the various `lookup_*` method that
+# allow to retrieve values trough the importation relation.
+class MModuleData[E: Object]
+       # The model associated with the data
+       # Used to execute correclty mmodule-related operation
+       var model: Model
+
+       # is a value locally defined in `mmodule`
+       fun has_mmodule(mmodule: MModule): Bool
+       do
+               return defs.has_key(mmodule)
+       end
+
+       # The value locally defined in `mmodule`.
+       # Return null if no value locally defined.
+       fun [](mmodule: MModule): nullable E
+       do
+               return defs.get_or_null(mmodule)
+       end
+
+       # Set the value locally defined in `mmodule`.
+       # Gining `null` just undefine the value
+       fun []=(mmodule: MModule, value: nullable E)
+       do
+               if value == null then
+                       defs.keys.remove(mmodule)
+               else
+                       defs[mmodule] = value
+               end
+       end
+
+       private var defs = new HashMap[MModule, E]
+
+       # Return all the super modules that defines a value
+       # `min_visibility` is used to filter modules by their visibility in `mmodule`.
+       fun lookup_all_modules(mmodule: MModule, min_visibility: MVisibility): Sequence[MModule]
+       do
+               var res = new Array[MModule]
+               for m in mmodule.in_importation.greaters do
+                       if mmodule.visibility_for(m) < min_visibility then continue
+                       if self.defs.has_key(m) then res.add(m)
+               end
+               return res
+       end
+
+       # Return all the values defined in `mmodule` and its imported modules.
+       # `min_visibility` is used to filter modules by their visibility in `mmodule`.
+       # This method could be usefull to check possible static conflicts.
+       fun lookup_all_values(mmodule: MModule, min_visibility: MVisibility): Sequence[E]
+       do
+               var mmodules = lookup_all_modules(mmodule, min_visibility)
+               mmodules = model.mmodule_importation_hierarchy.linearize(mmodules)
+               var res = new Array[E]
+               for m in mmodules do res.add defs[m]
+               return res
+       end
+
+       # Return the most specific values defined in `mmodule` and its imported modules.
+       # `min_visibility_` is used to filter modules by their visibility in `mmodule`.
+       # Unlike `lookup_all_values`, redefined values are hidden,
+       # However, in case of conflit, all conflicting definitions are returned
+       fun lookup_values(mmodule: MModule, min_visibility: MVisibility): Sequence[E]
+       do
+               var mmodules = lookup_all_modules(mmodule, min_visibility)
+               mmodules = model.mmodule_importation_hierarchy.select_smallest(mmodules)
+               var res = new Array[E]
+               for m in mmodules do res.add defs[m]
+               return res
+       end
+
+       # Return the most specific values defined in `mmodule` and its imported modules.
+       # Unlike `lookup_values`, only the most specific value, according to importation, is returned.
+       fun lookup_first_value(mmodule: MModule, min_visibility: MVisibility): nullable E
+       do
+               var mmodules = lookup_all_modules(mmodule, min_visibility)
+               if mmodules.is_empty then return null
+               mmodules = model.mmodule_importation_hierarchy.linearize(mmodules)
+               return defs[mmodules.last]
+       end
+end
+
+# A `MModuleData` where multiples values could be set on a single module
+# a-la `MultiHashMap`
+class MModuleMultiData[E]
+       super MModuleData[Array[E]]
+
+       # Instead of `null` return an empty array usable
+       redef fun [](mmodule)
+       do
+               var res = super
+               if res == null then
+                       res = new Array[E]
+                       defs[mmodule] = res
+               end
+               return res
+       end
+
+       # like `lookup_all_values` but return a big concatenated sequence (instead of a sequence of array)
+       fun lookup_joined_values(mmodule: MModule, min_visibility: MVisibility): Sequence[E]
+       do
+               var mmodules = lookup_all_modules(mmodule, min_visibility)
+               mmodules = model.mmodule_importation_hierarchy.linearize(mmodules)
+               var res = new Array[E]
+               for m in mmodules do res.add_all defs[m]
+               return res
+       end
+end