Don't ask me why it worked before...
Pull-Request: #767
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
end
end
-redef class String
- # escape string used in labels for graphviz
- fun escape_to_dot: String
- do
- return escape_more_to_c("|\{\}<>")
- end
-end
-
private class Generator
var out = new Array[String]
fun add(s: String) do out.add(s)
--- /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.
+
+# Mix of all things cryptography-related
+module crypto
+
+redef class Char
+ # Rotates self of `x`
+ #
+ # NOTE: works on letters only
+ #
+ # assert 'x'.rot(6) == 'd'
+ # assert 'T'.rot(15) == 'I'
+ # assert '1'.rot(10) == '1'
+ # assert '$'.rot(10) == '$'
+ # assert 'z'.rot(-2) == 'x'
+ fun rot(x: Int): Char do
+ if not is_letter then return self
+ x = x % 26
+ if x < 0 then x += 26
+ var up = false
+ var val = ascii
+ if is_upper then
+ up = true
+ val += 32
+ end
+ val += x
+ if val > 122 then val -= 26
+ if up then val -= 32
+ return val.ascii
+ end
+end
+
+redef class String
+ # Performs a Rotation of `x` on each letter of self
+ #
+ # Works by replacing every character in `self` by its
+ # rotated char.
+ #
+ # Say we have a rotation of `3` (Caesar rotation, for
+ # culture) for a string : "aybabtu"
+ #
+ # a, rotated by 3 becomes d
+ # y, rotated by 3 becomes b
+ # b, rotated by 3 becomes e
+ # t, rotated by 3 becomes w
+ # u, rotated by 3 becomes x
+ #
+ # We then replace every letter in our original string by
+ # their rotated representations, therefore yielding : "dbedewx"
+ #
+ # assert "All your base are belong to us".rot(13) == "Nyy lbhe onfr ner orybat gb hf"
+ # assert "This is no moon.".rot(4).rot(22) == "This is no moon."
+ #
+ # NOTE : Works on letters only
+ # NOTE : This cipher is symmetrically decrypted with an `x` of 26-`x`
+ fun rot(x: Int): String do
+ var rot = x % 26
+ if rot < 0 then rot += 26
+ var d = new FlatBuffer.with_capacity(length)
+ var p = 0
+ for i in chars do
+ d.add i.rot(rot)
+ end
+ return d.to_s
+ end
+
+ # Returns a rail-fence cipher from `self` with `depth` rails
+ #
+ # Rail works by drawing a zig-zag pattern on `depth` rails.
+ #
+ # Say we have "fuckingbehemoth".railfence(4)
+ #
+ # This happens in-memory :
+ # f.....g.....o..
+ # .u...n.b...m.t.
+ # ..c.i...e.e...h
+ # ...k.....h.....
+ #
+ # Therefore, yielding the ciphertext : "fgounbmtcieehkh"
+ #
+ # assert "fuckingbehemoth".railfence(4) == "fgounbmtcieehkh"
+ fun railfence(depth: Int): String do
+ var lines = new Array[FlatBuffer].with_capacity(depth)
+ var up = false
+ for i in [0..depth[ do
+ lines[i] = new FlatBuffer.with_capacity(length)
+ end
+ var curr_depth = 0
+ for i in chars do
+ for j in [0..depth[ do
+ if j == curr_depth then
+ lines[j].add i
+ else
+ lines[j].add '.'
+ end
+ end
+ if up then
+ curr_depth -= 1
+ else
+ curr_depth += 1
+ end
+ if curr_depth == 0 then
+ up = false
+ end
+ if curr_depth == (depth - 1) then
+ up = true
+ end
+ end
+ var r = new FlatBuffer.with_capacity(length)
+ for i in lines do
+ r.append i.to_s.replace(".", "")
+ end
+ return r.to_s
+ end
+
+ # Transforms a rail-fence-encrypted String to its original
+ #
+ # assert "fgounbmtcieehkh".unrail(4) == "fuckingbehemoth"
+ fun unrail(depth: Int): String do
+ var dots = "." * length
+ var arr = new FlatBuffer.from(dots)
+ var start = 0
+ var paces = depth.unrail_paces
+ for i in [0..depth[ do
+ var lp = paces[i].first
+ var rp = paces[i].second
+ var pos = i
+ var l = true
+ while pos < length do
+ arr[pos] = chars[start]
+ if l then
+ pos += lp
+ l = false
+ else
+ pos += rp
+ l = true
+ end
+ start += 1
+ end
+ end
+ return arr.to_s
+ end
+end
+
+redef class Int
+ # Generates the paces for each depth.
+ #
+ # Each entry of the returned array is a couple of the first pace
+ # and the second one, they are alternated when deciphering a rail-encrypted string.
+ #
+ # Say we have the encrypted string "fgounbmtcieehkh" on 4 rails
+ #
+ # To find the distance between each character on the original railed
+ # string, we need to compute the extremes.
+ #
+ # The extremes always have a distance of `depth - 1`, multiplied by 2, no pairing.
+ #
+ # In the example, that would be : [(4 - 1) * 2, (4 - 1) * 2] => [6,6]
+ #
+ # For every rail in-between, the first distance is the largest absolute value
+ # of the difference between the current depth and the extremes, multiplied by 2.
+ #
+ # Its pair is the distance of maximum and the distance yielded by the previous
+ # calculation.
+ #
+ # In our example, that would be :
+ #
+ # Maximums : (4 - 1) * 2 = 3 * 2 => [6,6]
+ # In between : Distance for depth 2 : max(2 - 1, 4 - 2) => 2
+ # The calculation yields the couple [(2 * 2), 6 - 4] => [4, 2]
+ # The symmetric couple is reversed : [2, 4]
+ #
+ # In fine, the example yields the array : [[6,6], [4,2], [2,4], [6,6]]
+ #
+ # In the end, our string is read using the generated array
+ #
+ # SEE: `String::unrail` for how the array is used
+ private fun unrail_paces: Array[Couple[Int, Int]] do
+ var ret = new Array[Couple[Int,Int]].with_capacity(self)
+ var extremes = new Couple[Int, Int]((self - 1) * 2, (self - 1) * 2)
+ for i in [0..self[ do
+ ret.add extremes
+ end
+ var mid = ((self.to_f)/2.0).floor.to_i
+ for i in [1 .. mid[ do
+ var rd = i + 1
+ var lodepth = self - rd
+ var hidepth = (rd - self).abs
+ var dd: Int
+ if hidepth > lodepth then
+ dd = hidepth * 2
+ else
+ dd = lodepth * 2
+ end
+ var cp = new Couple[Int, Int](dd, extremes.first-dd)
+ var ccp = new Couple[Int, Int](extremes.first - dd, dd)
+
+ ret[i] = cp
+ ret[self - rd] = ccp
+ end
+ if not self.is_even then
+ ret[mid] = new Couple[Int, Int](extremes.first/2, extremes.first/2)
+ end
+ return ret
+ end
+end
if self > o then return (self - o).rshift(1).gcd(o)
return (o - self).rshift(1).gcd(self)
end
+
+ # Is `self` even ?
+ #
+ # assert 12.is_even
+ fun is_even: Bool do return self % 2 == 0
+
+ # Is `self` odd ?
+ #
+ # assert not 13.is_even
+ fun is_odd: Bool do return not is_even
end
redef class Float
end
end
+ # Escape string used in labels for graphviz
+ #
+ # assert ">><<".escape_to_dot == "\\>\\>\\<\\<"
+ fun escape_to_dot: String
+ do
+ return escape_more_to_c("|\{\}<>")
+ end
+
# Flat representation of self
fun flatten: FlatText is abstract
# * `public_visibility`
# * `protected_visibility`
# * `none_visibility`
+# * `private_visiblity`
#
# Note this class is basically an enum.
# FIXME: use a real enum once user-defined enums are available
--- /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.
+
+# UML generator in dot format.
+module nituml
+
+import modelbuilder
+import frontend
+import uml
+
+redef class ToolContext
+ var umlphase: Phase = new UMLPhase(self, null)
+
+ var opt_gen = new OptionEnum(["class", "package"], "Choose which type of uml diagram to generate", 0, "--diagram")
+
+ redef init do
+ option_context.add_option opt_gen
+ super
+ end
+end
+
+private class UMLPhase
+ super Phase
+ redef fun process_mainmodule(mainmodule, mmodules)
+ do
+ var d = new UMLModel(mainmodule.model, mainmodule, toolcontext)
+ if toolcontext.opt_gen.value == 0 then
+ print d.generate_class_uml.write_to_string
+ else if toolcontext.opt_gen.value == 1 then
+ print d.generate_package_uml.write_to_string
+ end
+ end
+end
+
+# process options
+var toolcontext = new ToolContext
+toolcontext.process_options(args)
+var arguments = toolcontext.option_context.rest
+
+# build model
+var model = new Model
+var mbuilder = new ModelBuilder(model, toolcontext)
+var mmodules = mbuilder.parse(arguments)
+
+if mmodules.is_empty then return
+mbuilder.run_phases
+toolcontext.run_global_phases(mmodules)
--- /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.
+
+# Group head module for UML generation services
+module uml
+
+import uml_base
+import uml_class
+import uml_module
--- /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.
+
+# Exposes the base class for UML generation of a `Model`
+module uml_base
+
+import toolcontext
+import model_utils
+
+redef class ToolContext
+ # -p
+ var opt_privacy = new OptionBool("Generates private API", "-p", "--private")
+
+ # Shortcut for the value of `self.opt_privacy`
+ fun private_gen: Bool do return opt_privacy.value
+
+ redef init do
+ option_context.add_option opt_privacy
+ super
+ end
+end
+
+class UMLModel
+ var model: Model
+ var mainmodule: MModule
+ var ctx: ToolContext
+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.
+
+# Provides facilities of exporting a `Model` to a UML class diagram
+module uml_class
+
+import uml_base
+
+redef class UMLModel
+ # Generates a UML class diagram from a `Model`
+ fun generate_class_uml: Streamable do
+ var tpl = new Template
+ tpl.add "digraph G \{\n"
+ tpl.add """ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ node [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ shape = "record"
+ ]
+
+ edge [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ ]\n"""
+ tpl.add model.tpl_class(ctx, mainmodule)
+ tpl.add "\}"
+ return tpl
+ end
+end
+
+redef class Model
+
+ # Generates a UML Class diagram from the entities of a `Model`
+ fun tpl_class(ctx: ToolContext, main: MModule): Streamable do
+ var t = new Template
+ for i in mclasses do
+ if not ctx.private_gen and i.visibility != public_visibility then continue
+ t.add i.tpl_class(ctx, main)
+ t.add "\n"
+ end
+ return t
+ end
+
+end
+
+redef class MEntity
+ # Generates a dot-compatible `Streamable` UML Class diagram from `self`
+ fun tpl_class(ctx: ToolContext, main: MModule): Streamable is abstract
+end
+
+redef class MClass
+
+ redef fun tpl_class(ctx, main): Streamable do
+ var t = new Template
+ t.add "{name} [\n label = \"\{"
+ if kind == abstract_kind then
+ t.add "abstract\\n{name}"
+ else if kind == interface_kind then
+ t.add "interface\\n{name}"
+ else
+ t.add "{name}"
+ end
+ if arity > 0 then
+ t.add "["
+ var formal = intro.parameter_names
+ t.add formal.first
+ for i in [1 .. formal.length[ do
+ t.add ", "
+ t.add formal[i]
+ end
+ t.add "]"
+ end
+ t.add "|"
+ var props: Collection[MProperty]
+ if ctx.private_gen then
+ props = intro_mproperties(none_visibility)
+ else
+ props = intro_mproperties(public_visibility)
+ end
+ for i in props do
+ if i isa MAttribute then
+ t.add i.tpl_class(ctx, main)
+ t.add "\\l"
+ end
+ end
+ t.add "|"
+ for i in intro_methods do
+ if not ctx.private_gen and i.visibility != public_visibility then continue
+ t.add i.tpl_class(ctx, main)
+ t.add "\\l"
+ end
+ t.add "\}\"\n]\n"
+ var g = in_hierarchy(main).direct_greaters
+ for i in g do
+ if not ctx.private_gen and i.visibility != public_visibility then continue
+ t.add "{i.name} -> {name} [dir=back"
+ if i.kind == interface_kind then
+ t.add " arrowtail=open style=dashed"
+ else
+ t.add " arrowtail=empty"
+ end
+ t.add "];\n"
+ end
+ return t
+ end
+
+end
+
+redef class MMethod
+ redef fun tpl_class(ctx, main) do
+ var tpl = new Template
+ tpl.add visibility.tpl_class
+ tpl.add " "
+ tpl.add name.escape_to_dot
+ tpl.add intro.msignature.tpl_class(ctx, main)
+ return tpl
+ end
+end
+
+redef class MSignature
+
+ redef fun tpl_class(ctx, main) do
+ var t = new Template
+ t.add "("
+ var params = new Array[MParameter]
+ for i in mparameters do
+ params.add i
+ end
+ if params.length > 0 then
+ t.add params.first.name
+ t.add ": "
+ t.add params.first.mtype.tpl_class(ctx, main)
+ for i in [1 .. params.length [ do
+ t.add ", "
+ t.add params[i].name
+ t.add ": "
+ t.add params[i].mtype.tpl_class(ctx, main)
+ end
+ end
+ t.add ")"
+ if return_mtype != null then
+ t.add ": "
+ t.add return_mtype.tpl_class(ctx, main)
+ end
+ return t
+ end
+end
+
+redef class MAttribute
+ redef fun tpl_class(ctx, main) do
+ var tpl = new Template
+ tpl.add visibility.tpl_class
+ tpl.add " "
+ tpl.add name
+ tpl.add ": "
+ tpl.add intro.static_mtype.tpl_class(ctx, main)
+ return tpl
+ end
+end
+
+redef class MVisibility
+ # Returns the visibility as a UML token
+ #
+ # assert public_visibility.tpl_class == "+"
+ # assert private_visibility.tpl_class == "-"
+ fun tpl_class: Streamable do
+ if self == private_visibility then
+ return "-"
+ else if self == protected_visibility then
+ return "#"
+ else if self == public_visibility then
+ return "+"
+ else
+ return "+"
+ end
+ end
+end
+
+redef class MClassType
+ redef fun tpl_class(c, m) do
+ return name
+ end
+end
+
+redef class MGenericType
+ redef fun tpl_class(c, m) do
+ var t = new Template
+ t.add name.substring(0, name.index_of('['))
+ t.add "["
+ t.add arguments.first.tpl_class(c, m)
+ for i in [1 .. arguments.length[ do
+ t.add ", "
+ t.add arguments[i].tpl_class(c, m)
+ end
+ t.add "]"
+ return t
+ end
+end
+
+redef class MParameterType
+ redef fun tpl_class(c, m) do
+ var n = mclass.intro.parameter_names
+ return n[rank]
+ end
+end
+
+redef class MVirtualType
+ redef fun tpl_class(c, m) do
+ return name
+ end
+end
+
+redef class MNullableType
+ redef fun tpl_class(c, m) do
+ var t = new Template
+ t.add "nullable "
+ t.add mtype.tpl_class(c, m)
+ return t
+ 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.
+
+# Services for generation of a UML package diagram based on a `Model`
+module uml_module
+
+import uml_base
+import uml_class
+
+redef class UMLModel
+ # Generates a UML package diagram from a `Model`
+ fun generate_package_uml: Streamable do
+ var tpl = new Template
+ tpl.add "digraph G \{\n"
+ tpl.add """ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ node [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ shape = "record"
+ ]
+ edge [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ ]\n"""
+ tpl.add model.tpl_module(ctx, mainmodule)
+ tpl.add "\}"
+ return tpl
+ end
+end
+
+redef class Model
+ # Returns a UML package diagram of `main`
+ fun tpl_module(ctx: ToolContext, main: MModule): Streamable do
+ return main.tpl_module(ctx, main)
+ end
+end
+
+redef class MModule
+ redef fun tpl_module(ctx, main) do
+ var t = new Template
+ t.add "subgraph cluster{name} \{\n"
+ t.add "label = \"{name}\"\n"
+ for i in mclassdefs do
+ if not ctx.private_gen and i.mclass.visibility != public_visibility then continue
+ t.add i.tpl_module(ctx, main)
+ end
+ t.add "\}\n"
+ return t
+ end
+end
+
+redef class MEntity
+ # Builds a dot UML package diagram entity from `self`
+ fun tpl_module(ctx: ToolContext, main: MModule): Streamable is abstract
+end
+
+redef class MClassDef
+
+ # Colour for the border of a class when first introduced
+ #
+ # Defaults to a shade of green
+ var intro_colour = "#58B26A"
+
+ # Colour for the border of a class when refined
+ #
+ # Defaults to a shade of red
+ var redef_colour = "#B24758"
+
+ redef fun tpl_module(ctx, main) do
+ var t = new Template
+ t.add "{mmodule}{name} [\n\tlabel = \"\{"
+ if mclass.kind == abstract_kind then
+ t.add "abstract\\n{name}"
+ else if mclass.kind == interface_kind then
+ t.add "interface\\n{name}"
+ else
+ t.add "{name}"
+ end
+ if mclass.arity > 0 then
+ t.add "["
+ var formal = mclass.intro.parameter_names
+ t.add formal.first
+ for i in [1 .. formal.length[ do
+ t.add ", "
+ t.add formal[i]
+ end
+ t.add "]"
+ end
+ t.add "|"
+ for i in mpropdefs do
+ if not i isa MAttributeDef then continue
+ if not ctx.private_gen and i.mproperty.visibility != public_visibility then continue
+ t.add i.tpl_module(ctx, main)
+ t.add "\\l"
+ end
+ t.add "|"
+ for i in mpropdefs do
+ if not i isa MMethodDef then continue
+ if not ctx.private_gen and i.mproperty.visibility != public_visibility then continue
+ t.add i.tpl_module(ctx, main)
+ t.add "\\l"
+ end
+ t.add "\}\""
+ if is_intro then
+ t.add "color=\"{intro_colour}\""
+ else
+ t.add "color=\"{redef_colour}\""
+ end
+ t.add "\n]\n"
+ var supers = in_hierarchy.direct_greaters
+ for i in supers do
+ if i.mmodule != mmodule then continue
+ t.add "{i.mmodule}{i.name} -> {mmodule}{name} [dir=back"
+ if i.mclass.kind == interface_kind then
+ t.add " arrowtail=open style=dashed"
+ else
+ t.add " arrowtail=empty"
+ end
+ t.add "]\n"
+ end
+ return t
+ end
+end
+
+redef class MMethodDef
+ redef fun tpl_module(ctx, main) do
+ var t = new Template
+ t.add mproperty.visibility.tpl_class
+ t.add " "
+ t.add name.escape_to_dot
+ t.add msignature.tpl_class(ctx, main)
+ return t
+ end
+end
+
+redef class MAttributeDef
+ redef fun tpl_module(ctx, main) do
+ var t = new Template
+ t.add mproperty.visibility.tpl_class
+ t.add " "
+ t.add name
+ t.add ": "
+ t.add static_mtype.tpl_class(ctx, main)
+ return t
+ end
+end
--- /dev/null
+--diagram package --private ./base_prot_sig2.nit -I ../lib/standard
+--diagram package ./base_prot_sig2.nit -I ../lib/standard
+--diagram class --private ./base_prot_sig2.nit -I ../lib/standard
+--diagram class ./base_prot_sig2.nit -I ../lib/standard
--- /dev/null
+Usage: [OPTION]... [ARG]...
+Use --help for help
--- /dev/null
+digraph G {
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ node [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ shape = "record"
+ ]
+ edge [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ ]
+subgraph clusterbase_prot_sig2 {
+label = "base_prot_sig2"
+base_prot_sig2C [
+ label = "{C|- _vpriA: nullable A\l- _vpriA2: A\l|- priA(a: A)\l- vpriA(): nullable A\l- vpriA=(vpriA: nullable A)\l- vpriA2(): A\l- vpriA2=(vpriA2: A)\l+ init()\l}"color="#58B26A"
+]
+base_prot_sig2D [
+ label = "{D|- _vpubA: nullable A\l- _vpriA: nullable A\l- _vpubA2: A\l- _vpriA2: A\l|- pubA(a: A)\l- priA(a: A)\l- vpubA(): nullable A\l- vpubA=(vpubA: nullable A)\l- vpriA(): nullable A\l- vpriA=(vpriA: nullable A)\l- vpubA2(): A\l- vpubA2=(vpubA2: A)\l- vpriA2(): A\l- vpriA2=(vpriA2: A)\l+ init()\l}"color="#58B26A"
+]
+}
+}
--- /dev/null
+digraph G {
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ node [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ shape = "record"
+ ]
+ edge [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ ]
+subgraph clusterbase_prot_sig2 {
+label = "base_prot_sig2"
+base_prot_sig2C [
+ label = "{C||+ init()\l}"color="#58B26A"
+]
+}
+}
--- /dev/null
+digraph G {
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ node [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ shape = "record"
+ ]
+
+ edge [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ ]
+Object [
+ label = "{interface\nObject||+ object_id(): Int\l+ is_same_type(other: Object): Bool\l+ is_same_instance(other: nullable Object): Bool\l+ ==(other: nullable Object): Bool\l+ !=(other: nullable Object): Bool\l+ output()\l+ output_class_name()\l+ hash(): Int\l+ exit(exit_value: Int)\l+ sys(): Sys\l}"
+]
+
+Sys [
+ label = "{Sys||+ main()\l+ run()\l+ errno(): Int\l}"
+]
+Object -> Sys [dir=back arrowtail=open style=dashed];
+
+Comparable [
+ label = "{interface\nComparable||+ \<(other: OTHER): Bool\l+ \<=(other: OTHER): Bool\l+ \>=(other: OTHER): Bool\l+ \>(other: OTHER): Bool\l+ \<=\>(other: OTHER): Int\l+ is_between(c: OTHER, d: OTHER): Bool\l+ max(other: OTHER): OTHER\l+ min(c: OTHER): OTHER\l}"
+]
+Object -> Comparable [dir=back arrowtail=open style=dashed];
+
+Discrete [
+ label = "{interface\nDiscrete||+ successor(i: Int): OTHER\l+ predecessor(i: Int): OTHER\l+ distance(d: OTHER): Int\l}"
+]
+Comparable -> Discrete [dir=back arrowtail=open style=dashed];
+
+Numeric [
+ label = "{interface\nNumeric||+ +(i: OTHER): OTHER\l+ -(i: OTHER): OTHER\l+ unary -(): OTHER\l+ *(i: OTHER): OTHER\l+ /(i: OTHER): OTHER\l+ to_i(): Int\l+ to_f(): Float\l+ is_zero(): Bool\l+ zero(): OTHER\l+ value_of(val: Numeric): OTHER\l}"
+]
+Comparable -> Numeric [dir=back arrowtail=open style=dashed];
+
+Bool [
+ label = "{Bool||+ to_i(): Int\l}"
+]
+Object -> Bool [dir=back arrowtail=open style=dashed];
+
+Float [
+ label = "{Float||}"
+]
+Numeric -> Float [dir=back arrowtail=open style=dashed];
+
+Int [
+ label = "{Int||+ %(i: Int): Int\l+ lshift(i: Int): Int\l+ rshift(i: Int): Int\l+ ascii(): Char\l+ digit_count(b: Int): Int\l+ digit_count_base_10(): Int\l+ to_c(): Char\l+ abs(): Int\l}"
+]
+Discrete -> Int [dir=back arrowtail=open style=dashed];
+Numeric -> Int [dir=back arrowtail=open style=dashed];
+
+Char [
+ label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l}"
+]
+Discrete -> Char [dir=back arrowtail=open style=dashed];
+
+Pointer [
+ label = "{Pointer||+ address_is_null(): Bool\l+ free()\l}"
+]
+Object -> Pointer [dir=back arrowtail=open style=dashed];
+
+A [
+ label = "{A|- _vpubA: nullable A\l- _vproA: nullable A\l- _vpriA: nullable A\l- _vpubA2: A\l- _vproA2: A\l- _vpriA2: A\l- _vpriB: nullable B\l- _vpriB2: B\l|+ pubA(a: A)\l# proA(a: A)\l- priA(a: A)\l+ vpubA(): nullable A\l+ vpubA=(vpubA: nullable A)\l# vproA(): nullable A\l# vproA=(vproA: nullable A)\l- vpriA(): nullable A\l- vpriA=(vpriA: nullable A)\l+ vpubA2(): A\l+ vpubA2=(vpubA2: A)\l# vproA2(): A\l# vproA2=(vproA2: A)\l- vpriA2(): A\l- vpriA2=(vpriA2: A)\l- priB(a: B)\l- vpriB(): nullable B\l- vpriB=(vpriB: nullable B)\l- vpriB2(): B\l- vpriB2=(vpriB2: B)\l}"
+]
+Object -> A [dir=back arrowtail=open style=dashed];
+
+B [
+ label = "{B|- _vpubA: nullable A\l- _vpriA: nullable A\l- _vpubA2: A\l- _vpriA2: A\l- _vpubB: nullable B\l- _vpriB: nullable B\l- _vpubB2: B\l- _vpriB2: B\l|- pubA(a: A)\l- priA(a: A)\l- vpubA(): nullable A\l- vpubA=(vpubA: nullable A)\l- vpriA(): nullable A\l- vpriA=(vpriA: nullable A)\l- vpubA2(): A\l- vpubA2=(vpubA2: A)\l- vpriA2(): A\l- vpriA2=(vpriA2: A)\l- pubB(a: B)\l- priB(a: B)\l- vpubB(): nullable B\l- vpubB=(vpubB: nullable B)\l- vpriB(): nullable B\l- vpriB=(vpriB: nullable B)\l- vpubB2(): B\l- vpubB2=(vpubB2: B)\l- vpriB2(): B\l- vpriB2=(vpriB2: B)\l}"
+]
+Object -> B [dir=back arrowtail=open style=dashed];
+
+C [
+ label = "{C|- _vpriA: nullable A\l- _vpriA2: A\l|- priA(a: A)\l- vpriA(): nullable A\l- vpriA=(vpriA: nullable A)\l- vpriA2(): A\l- vpriA2=(vpriA2: A)\l}"
+]
+Object -> C [dir=back arrowtail=open style=dashed];
+
+D [
+ label = "{D|- _vpubA: nullable A\l- _vpriA: nullable A\l- _vpubA2: A\l- _vpriA2: A\l|- pubA(a: A)\l- priA(a: A)\l- vpubA(): nullable A\l- vpubA=(vpubA: nullable A)\l- vpriA(): nullable A\l- vpriA=(vpriA: nullable A)\l- vpubA2(): A\l- vpubA2=(vpubA2: A)\l- vpriA2(): A\l- vpriA2=(vpriA2: A)\l}"
+]
+Object -> D [dir=back arrowtail=open style=dashed];
+
+}
--- /dev/null
+digraph G {
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ node [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ shape = "record"
+ ]
+
+ edge [
+ fontname = "Bitstream Vera Sans"
+ fontsize = 8
+ ]
+Object [
+ label = "{interface\nObject||+ object_id(): Int\l+ is_same_type(other: Object): Bool\l+ is_same_instance(other: nullable Object): Bool\l+ ==(other: nullable Object): Bool\l+ !=(other: nullable Object): Bool\l+ output()\l+ output_class_name()\l+ hash(): Int\l+ exit(exit_value: Int)\l+ sys(): Sys\l}"
+]
+
+Sys [
+ label = "{Sys||+ main()\l+ run()\l+ errno(): Int\l}"
+]
+Object -> Sys [dir=back arrowtail=open style=dashed];
+
+Comparable [
+ label = "{interface\nComparable||+ \<(other: OTHER): Bool\l+ \<=(other: OTHER): Bool\l+ \>=(other: OTHER): Bool\l+ \>(other: OTHER): Bool\l+ \<=\>(other: OTHER): Int\l+ is_between(c: OTHER, d: OTHER): Bool\l+ max(other: OTHER): OTHER\l+ min(c: OTHER): OTHER\l}"
+]
+Object -> Comparable [dir=back arrowtail=open style=dashed];
+
+Discrete [
+ label = "{interface\nDiscrete||+ successor(i: Int): OTHER\l+ predecessor(i: Int): OTHER\l+ distance(d: OTHER): Int\l}"
+]
+Comparable -> Discrete [dir=back arrowtail=open style=dashed];
+
+Numeric [
+ label = "{interface\nNumeric||+ +(i: OTHER): OTHER\l+ -(i: OTHER): OTHER\l+ unary -(): OTHER\l+ *(i: OTHER): OTHER\l+ /(i: OTHER): OTHER\l+ to_i(): Int\l+ to_f(): Float\l+ is_zero(): Bool\l+ zero(): OTHER\l+ value_of(val: Numeric): OTHER\l}"
+]
+Comparable -> Numeric [dir=back arrowtail=open style=dashed];
+
+Bool [
+ label = "{Bool||+ to_i(): Int\l}"
+]
+Object -> Bool [dir=back arrowtail=open style=dashed];
+
+Float [
+ label = "{Float||}"
+]
+Numeric -> Float [dir=back arrowtail=open style=dashed];
+
+Int [
+ label = "{Int||+ %(i: Int): Int\l+ lshift(i: Int): Int\l+ rshift(i: Int): Int\l+ ascii(): Char\l+ digit_count(b: Int): Int\l+ digit_count_base_10(): Int\l+ to_c(): Char\l+ abs(): Int\l}"
+]
+Discrete -> Int [dir=back arrowtail=open style=dashed];
+Numeric -> Int [dir=back arrowtail=open style=dashed];
+
+Char [
+ label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l}"
+]
+Discrete -> Char [dir=back arrowtail=open style=dashed];
+
+Pointer [
+ label = "{Pointer||+ address_is_null(): Bool\l+ free()\l}"
+]
+Object -> Pointer [dir=back arrowtail=open style=dashed];
+
+A [
+ label = "{A||+ pubA(a: A)\l+ vpubA(): nullable A\l+ vpubA=(vpubA: nullable A)\l+ vpubA2(): A\l+ vpubA2=(vpubA2: A)\l}"
+]
+Object -> A [dir=back arrowtail=open style=dashed];
+
+C [
+ label = "{C||}"
+]
+Object -> C [dir=back arrowtail=open style=dashed];
+
+}