# `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.
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
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
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
--- /dev/null
+# 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
module model::class_compound
import graph
+import member
import type_entity
# A class.
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
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
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)
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
--- /dev/null
+# 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
import graph
import class_compound
import module_compound
+import member