neo_doxygen: List members.
authorJean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
Tue, 4 Nov 2014 14:33:25 +0000 (09:33 -0500)
committerJean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
Tue, 4 Nov 2014 17:16:06 +0000 (12:16 -0500)
Signed-off-by: Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>

contrib/neo_doxygen/src/doxml/compounddef.nit
contrib/neo_doxygen/src/doxml/memberdef.nit [new file with mode: 0644]
contrib/neo_doxygen/src/model/class_compound.nit
contrib/neo_doxygen/src/model/member.nit [new file with mode: 0644]
contrib/neo_doxygen/src/model/model.nit

index b95ee14..21d8d3c 100644 (file)
 # `compounddef` element reading.
 module doxml::compounddef
 
-import entitydef
+import memberdef
+import more_collections
 
 # Processes the content of a `compounddef` element.
 class CompoundDefListener
        super EntityDefListener
 
        var compound: Compound is writable, noinit
+       private var memberdef: MemberDefListener is noinit
+
+       # Default attributes for members in the current section.
+       private var member_defaults: MemberDefaults is noinit
+
+       # For each section kind, default attributes for member in that section.
+       private var section_kinds: DefaultMap[String, MemberDefaults] is noinit
 
 
        # Attributes of the current `<basecompoundref>` element.
@@ -33,6 +41,50 @@ class CompoundDefListener
 
        init do
                super
+               var defaults = new MemberDefaults("public", false, false)
+
+               memberdef = new MemberDefListener(reader, self)
+
+               member_defaults = defaults
+               section_kinds = new DefaultMap[String, MemberDefaults](defaults)
+
+               section_kinds["public-type"] = defaults
+               section_kinds["public-func"] = defaults
+               section_kinds["public-attrib"] = defaults
+               section_kinds["public-slot"] = defaults
+               defaults = new MemberDefaults("public", true, false)
+               section_kinds["public-static-func"] = defaults
+               section_kinds["public-static-attrib"] = defaults
+
+               defaults = new MemberDefaults("protected", false, false)
+               section_kinds["protected-type"] = defaults
+               section_kinds["protected-func"] = defaults
+               section_kinds["protected-attrib"] = defaults
+               section_kinds["protected-slot"] = defaults
+               defaults = new MemberDefaults("protected", true, false)
+               section_kinds["protected-static-func"] = defaults
+               section_kinds["protected-static-attrib"] = defaults
+
+               defaults = new MemberDefaults("package", false, false)
+               section_kinds["package-type"] = defaults
+               section_kinds["package-func"] = defaults
+               section_kinds["package-attrib"] = defaults
+               defaults = new MemberDefaults("package", true, false)
+               section_kinds["package-static-func"] = defaults
+               section_kinds["package-static-attrib"] = defaults
+
+               defaults = new MemberDefaults("private", false, false)
+               section_kinds["private-type"] = defaults
+               section_kinds["private-func"] = defaults
+               section_kinds["private-attrib"] = defaults
+               section_kinds["private-slot"] = defaults
+               defaults = new MemberDefaults("private", true, false)
+               section_kinds["private-static-func"] = defaults
+               section_kinds["private-static-attrib"] = defaults
+
+               defaults = new MemberDefaults("public", true, true)
+               section_kinds["related"] = defaults
+               section_kinds["user-defined"] = defaults
        end
 
        redef fun entity: Entity do return compound
@@ -48,6 +100,13 @@ class CompoundDefListener
                        prot = get_optional(atts, "prot", "")
                        virt = get_optional(atts, "virt", "")
                        text.listen_until(dox_uri, local_name)
+               else if "memberdef" == local_name then
+                       read_member(atts)
+               else if local_name == "sectiondef" then
+                       member_defaults = section_kinds[get_required(atts, "kind")]
+                       if member_defaults.is_special then
+                               super # TODO
+                       end
                else
                        super
                end
@@ -62,10 +121,43 @@ class CompoundDefListener
                        compound.declare_class(refid, text.to_s)
                else if local_name == "innernamespace" then
                        compound.declare_namespace(refid, text.to_s)
+               else if "memberdef" == local_name then
+                       if not (memberdef.member isa UnknownMember) then
+                               compound.declare_member(memberdef.member)
+                       end
                else if local_name == "basecompoundref" then
                        compound.declare_super(refid, text.to_s, prot, virt)
                else
                        super
                end
        end
+
+       private fun read_member(atts: Attributes) do
+               var kind = get_required(atts, "kind")
+
+               create_member(kind)
+               memberdef.member.model_id = get_required(atts, "id")
+               memberdef.member.visibility = get_optional(atts, "prot",
+                               member_defaults.visibility)
+       end
+
+       private fun create_member(kind: String) do
+               if kind == "variable" then
+                       memberdef.member = new Attribute(compound.graph)
+               else if kind == "function" then
+                       memberdef.member = new Method(compound.graph)
+               else
+                       memberdef.member = new UnknownMember(compound.graph)
+                       noop.listen_until(dox_uri, "memberdef")
+                       return
+               end
+               memberdef.listen_until(dox_uri, "memberdef")
+       end
+end
+
+# Default attributes for members in the current section.
+private class MemberDefaults
+       var visibility: String
+       var is_static: Bool
+       var is_special: Bool
 end
diff --git a/contrib/neo_doxygen/src/doxml/memberdef.nit b/contrib/neo_doxygen/src/doxml/memberdef.nit
new file mode 100644 (file)
index 0000000..57d95b9
--- /dev/null
@@ -0,0 +1,57 @@
+# 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.
+
+# `memberdef` element reading.
+module doxml::memberdef
+
+import entitydef
+
+# Processes the content of a `<memberdef>` element.
+class MemberDefListener
+       super EntityDefListener
+
+       # The current member.
+       var member: Member is writable, noinit
+
+       init do
+               super
+       end
+
+       redef fun entity do return member
+
+       redef fun start_dox_element(local_name: String, atts: Attributes) do
+               if "name" == local_name then
+                       text.listen_until(dox_uri, local_name)
+               else if "reimplements" == local_name then
+                       member.reimplement(get_required(atts, "refid"))
+               else if "type" == local_name then
+                       text.listen_until(dox_uri, local_name)
+                       # TODO links
+               else
+                       super
+               end
+       end
+
+       redef fun end_dox_element(local_name: String) do
+               if "memberdef" == local_name then
+                       member.put_in_graph
+               else if "name" == local_name then
+                       member.name = text.to_s
+               else if "type" == local_name then
+                       # TODO
+               else
+                       super
+               end
+       end
+end
index 7f2f0ab..986695e 100644 (file)
@@ -16,6 +16,7 @@
 module model::class_compound
 
 import graph
+import member
 import type_entity
 
 # A class.
@@ -75,6 +76,10 @@ class ClassCompound
                class_def.declare_super(id, name, prot, virt)
        end
 
+       redef fun declare_member(member: Member) do
+               class_def.declare_member(member)
+       end
+
        redef fun put_in_graph do
                super
                class_type.put_in_graph
@@ -101,10 +106,12 @@ class ClassDef
 
        var class_compound: ClassCompound
        var supers: SimpleCollection[String] = new Array[String]
+       var members: SimpleCollection[Member] = new Array[Member]
 
        init do
                super
                self.labels.add("MClassDef")
+               self["is_intro"] = true
        end
 
        fun declare_super(id: String, name: String, prot: String, virt: String) do
@@ -114,6 +121,29 @@ class ClassDef
                end
        end
 
+       fun declare_member(member: Member) do
+               var full_name = self["full_name"]
+
+               if full_name != null then
+                       member.parent_name = full_name.to_s
+               end
+               members.add(member)
+       end
+
+       redef fun full_name=(full_name: String) do
+               super
+               for m in members do
+                       m.parent_name = full_name
+               end
+       end
+
+       redef fun parent_name=(parent_name: String) do
+               super
+               for m in members do
+                       m.parent_name = full_name
+               end
+       end
+
        redef fun put_edges do
                super
                graph.add_edge(self, "BOUNDTYPE", class_compound.class_type)
@@ -121,6 +151,14 @@ class ClassDef
                for s in supers do
                        graph.add_edge(self, "INHERITS", graph.by_id[s].as(ClassCompound).class_type)
                end
+               for m in members do
+                       if m.is_intro then
+                               var intro = m.introducer.as(not null)
+                               graph.add_edge(self, "INTRODUCES", intro)
+                               graph.add_edge(intro, "INTRO_CLASSDEF", self)
+                       end
+                       graph.add_edge(self, "DECLARES", m)
+               end
        end
 end
 
diff --git a/contrib/neo_doxygen/src/model/member.nit b/contrib/neo_doxygen/src/model/member.nit
new file mode 100644 (file)
index 0000000..f29892e
--- /dev/null
@@ -0,0 +1,288 @@
+# 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.
+
+# Members.
+module model::member
+
+import graph
+import type_entity
+
+# A member.
+abstract class Member
+       super CodeBlock
+
+       # The node used to represent the `MProperty` node.
+       #
+       # Only defined if `self` is at the root of a reimplementation graph, and
+       # only once `put_in_graph` is called.
+       var introducer: nullable MemberIntroducer = null
+
+       # Members that this member redefines/reimplements.
+       var reimplemented: SimpleCollection[String] = new Array[String]
+
+       init do
+               super
+               self.labels.add("MPropDef")
+       end
+
+       # Set the static type.
+       fun static_type=(static_type: nullable TypeEntity) is abstract
+
+       # Get the static type.
+       fun static_type: nullable TypeEntity is abstract
+
+       # Append the specified parameter to the signature.
+       fun add_parameter(parameter: MemberParameter) do end
+
+       # Append a member that is reimplemeneted by `self`.
+       fun reimplement(parent: String) do
+               reimplemented.add(parent)
+       end
+
+       # Does this member introduce the property?
+       fun is_intro: Bool do
+               return reimplemented.length <= 0
+       end
+
+       redef fun put_in_graph do
+               super
+               self["is_intro"] = is_intro
+               if is_intro then
+                       var visibility = self["visibility"]
+                       var full_name = self["full_name"]
+                       var name = self["name"]
+
+                       introducer = create_introducer
+                       if full_name isa String then
+                               introducer.full_name = full_name
+                       else if name isa String then
+                               introducer.name = name
+                       end
+                       if visibility isa String then
+                               introducer.visibility = visibility
+                       end
+                       introducer.put_in_graph
+               end
+       end
+
+       redef fun put_edges do
+               super
+               var intro = resolve_introducer
+
+               assert intro != null
+               graph.add_edge(self, "DEFINES", intro)
+       end
+
+       # Set the visibility.
+       fun visibility=(visibility: String) do
+               self["visibility"] = visibility
+               if introducer != null then
+                       introducer.as(not null).visibility = visibility
+               end
+       end
+
+       redef fun name=(name: String) do
+               super
+               if introducer != null then
+                       introducer.as(not null).name = name
+               end
+       end
+
+       redef fun full_name=(full_name: String) do
+               super
+               if introducer != null then
+                       introducer.as(not null).full_name = full_name
+               end
+       end
+
+       redef fun parent_name=(parent_name: String) do
+               super
+               if introducer != null then
+                       introducer.as(not null).parent_name = parent_name
+               end
+       end
+
+       # Is the member abstract?
+       fun is_abstract=(is_abstract: Bool) do
+               self["is_abstract"] = is_abstract
+       end
+
+       # Create an instance of `MemberIntroducer` that will be linked to `self`.
+       protected fun create_introducer: MemberIntroducer is abstract
+
+       # Find the nearest reimplementation root.
+       #
+       #     var g = new ProjectGraph("foo")
+       #     var m1 = new Attribute(g)
+       #     var m2 = new Attribute(g)
+       #     var m3 = new Attribute(g)
+       #     #
+       #     m1.model_id = "1"
+       #     m1.put_in_graph
+       #     m2.reimplement("1")
+       #     m2.put_in_graph
+       #     assert m1.resolve_introducer == m1.introducer
+       #     assert m2.resolve_introducer == m1.introducer
+       #     #
+       #     m3.model_id = "3"
+       #     m3.reimplement("3")
+       #     m3.put_in_graph
+       #     assert m3.resolve_introducer == null
+       fun resolve_introducer: nullable MemberIntroducer do
+               if introducer == null then
+                       var member_queue = new List[String]
+                       var visited = new HashSet[Member]
+                       var member: Member
+
+                       member_queue.add_all(reimplemented)
+                       while not member_queue.is_empty do
+                               member = graph.by_id[member_queue.shift].as(Member)
+                               if visited.has(member) then
+                                       return null
+                               else if member.is_intro then
+                                       return member.introducer
+                               else
+                                       visited.add(member)
+                                       member_queue.add_all(member.reimplemented)
+                               end
+                       end
+                       return null
+               else
+                       return introducer
+               end
+       end
+end
+
+# An unrecognized member.
+#
+# Used to simplify the handling of ignored entities.
+class UnknownMember
+       super Member
+
+       redef fun put_in_graph do end
+       redef fun put_edges do end
+end
+
+class Method
+       super Member
+
+       # The method’s signature.
+       var signature: Signature is noinit, writable
+
+       init do
+               super
+               self.labels.add("MMethodDef")
+               self["is_intern"] = false # TODO
+               self["is_extern"] = false # TODO
+               signature = new Signature(graph)
+               is_abstract = false
+       end
+
+       # Set the return type.
+       redef fun static_type=(static_type: nullable TypeEntity) do
+               signature.return_type = static_type
+       end
+
+       # Get the return type.
+       redef fun static_type: nullable TypeEntity do return signature.return_type
+
+       redef fun add_parameter(parameter: MemberParameter) do
+               signature.parameters.add(parameter)
+       end
+
+       redef fun create_introducer: MemberIntroducer do
+               return new MethodIntroducer(graph)
+       end
+
+       redef fun put_in_graph do
+               super
+               signature.put_in_graph
+       end
+
+       redef fun put_edges do
+               super
+               graph.add_edge(self, "SIGNATURE", signature)
+       end
+end
+
+class Attribute
+       super Member
+
+       # The declared type.
+       redef var static_type: nullable TypeEntity = null is writable
+
+       init do
+               super
+               self.labels.add("MAttributeDef")
+       end
+
+       redef fun create_introducer: MemberIntroducer do
+               return new AttributeIntroducer(graph)
+       end
+
+       redef fun put_in_graph do
+               super
+               if static_type != null then
+                       static_type.as(not null).put_in_graph
+               end
+       end
+
+       redef fun put_edges do
+               super
+               if static_type != null then
+                       graph.add_edge(self, "TYPE", static_type.as(not null))
+               end
+       end
+end
+
+# The `MProperty` node of a root of a reimplementation graph.
+abstract class MemberIntroducer
+       super Entity
+
+       init do
+               super
+               self.labels.add("MProperty")
+               self["visibility"] = "public"
+       end
+
+       fun visibility=(visibility: String) do
+               self["visibility"] = visibility
+       end
+end
+
+# A `MProperty` node for a method.
+class MethodIntroducer
+       super MemberIntroducer
+
+       init do
+               super
+               self.labels.add("MMethod")
+               self["is_init"] = false # TODO
+       end
+end
+
+# A `MProperty` node for an attribute.
+class AttributeIntroducer
+       super MemberIntroducer
+
+       init do
+               super
+               self.labels.add("MAttribute")
+       end
+end
+
+redef class Compound
+       # Append the specified member.
+       fun declare_member(member: Member) do end
+end
index 443259e..6cc6dc7 100644 (file)
@@ -19,3 +19,4 @@ import location
 import graph
 import class_compound
 import module_compound
+import member