#
# TODO: better doc
#
-# TODO: liearization, closures, extern stuff
+# TODO: liearization, extern stuff
# FIXME: better handling of the types
module model
import poset
import location
-import model_base
+import mmodule
+import mdoc
private import more_collections
redef class Model
print("Fatal Error: no primitive class {name}")
exit(1)
end
- assert cla.length == 1 else print cla.join(", ")
+ if cla.length != 1 then
+ var msg = "Fatal Error: more than one primitive class {name}:"
+ for c in cla do msg += " {c.full_name}"
+ print msg
+ exit(1)
+ end
return cla.first
end
# belong to a hierarchy since the property and the
# hierarchy of a class depends of a module.
class MClass
+ super MEntity
+
# The module that introduce the class
# While classes are not bound to a specific module,
# the introducing module is used for naming an visibility
# class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
# a specific module
class MClassDef
+ super MEntity
+
# The module where the definition is
var mmodule: MModule
# * foo(anchor, mmodule, othertype)
# * foo(othertype, mmodule, anchor)
abstract class MType
+ super MEntity
# The model of the type
fun model: Model is abstract
# Return true if `self` is an subtype of `sup`.
# The typing is done using the standard typing policy of Nit.
#
- # REQUIRE: `anchor == null` implies `not self.need_anchor and not sup.need_anchor`
- # REQUIRE: `anchor != null` implies `self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
+ # REQUIRE: `anchor == null implies not self.need_anchor and not sup.need_anchor`
+ # REQUIRE: `anchor != null implies self.can_resolve_for(anchor, null, mmodule) and sup.can_resolve_for(anchor, null, mmodule)`
fun is_subtype(mmodule: MModule, anchor: nullable MClassType, sup: MType): Bool
do
var sub = self
# because "redef type U: Y". Therefore, Map[T, U] is bound to
# Map[B, Y]
#
- # ENSURE: `not self.need_anchor` implies `result == self`
+ # ENSURE: `not self.need_anchor implies result == self`
# ENSURE: `not result.need_anchor`
fun anchor_to(mmodule: MModule, anchor: MClassType): MType
do
# H[Int] supertype_to G #-> G[Int, Bool]
#
# REQUIRE: `super_mclass` is a super-class of `self`
- # REQUIRE: `self.need_anchor` implies `anchor != null and self.can_resolve_for(anchor, null, mmodule)`
+ # REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
# ENSURE: `result.mclass = super_mclass`
fun supertype_to(mmodule: MModule, anchor: nullable MClassType, super_mclass: MClass): MClassType
do
# two function instead of one seems also to be a bad idea.
#
# REQUIRE: `can_resolve_for(mtype, anchor, mmodule)`
- # ENSURE: `not self.need_anchor` implies `result == self`
+ # ENSURE: `not self.need_anchor implies result == self`
fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract
# Can the type be resolved?
# B[E] is a red hearing only the E is important,
# E make sense in A
#
- # REQUIRE: `anchor != null` implies `not anchor.need_anchor`
- # REQUIRE: `mtype.need_anchor` implies `anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
- # ENSURE: `not self.need_anchor` implies `result == true`
+ # REQUIRE: `anchor != null implies not anchor.need_anchor`
+ # REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
+ # ENSURE: `not self.need_anchor implies result == true`
fun can_resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule): Bool is abstract
# Return the nullable version of the type
redef fun collect_mtypes(mmodule) do return new HashSet[MClassType]
end
-# A signature of a method (or a closure)
+# A signature of a method
class MSignature
super MType
# The each parameter (in order)
var mparameters: Array[MParameter]
- var mclosures = new Array[MParameter]
-
# The return type (null for a procedure)
var return_mtype: nullable MType
var d = p.mtype.depth
if d > dmax then dmax = d
end
- for p in mclosures do
- var d = p.mtype.depth
- if d > dmax then dmax = d
- end
return dmax + 1
end
for p in mparameters do
res += p.mtype.length
end
- for p in mclosures do
- res += p.mtype.length
- end
return res
end
redef fun to_s
do
- var b = new Buffer
+ var b = new FlatBuffer
if not mparameters.is_empty then
b.append("(")
for i in [0..mparameters.length[ do
ret = ret.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
end
var res = new MSignature(params, ret)
- for p in self.mclosures do
- res.mclosures.add(p.resolve_for(mtype, anchor, mmodule, cleanup_virtual))
- end
return res
end
end
# Is the parameter a vararg?
var is_vararg: Bool
+ redef fun to_s
+ do
+ if is_vararg then
+ return "{name}: {mtype}..."
+ else
+ return "{name}: {mtype}"
+ end
+ end
+
fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
do
if not self.mtype.need_anchor then return self
# of any dynamic type).
# For instance, a call site "x.foo" is associated to a `MProperty`.
abstract class MProperty
+ super MEntity
+
# The associated MPropDef subclass.
# The two specialization hierarchy are symmetric.
type MPROPDEF: MPropDef
end
# Second, filter the most specific ones
- var res = new Array[MPROPDEF]
- for pd1 in candidates do
- var cd1 = pd1.mclassdef
- var c1 = cd1.mclass
- var keep = true
- for pd2 in candidates do
- if pd2 == pd1 then continue # do not compare with self!
- var cd2 = pd2.mclassdef
- var c2 = cd2.mclass
- if c2.mclass_type == c1.mclass_type then
- if cd2.mmodule.in_importation <= cd1.mmodule then
- # cd2 refines cd1; therefore we skip pd1
- keep = false
- break
- end
- else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
- # cd2 < cd1; therefore we skip pd1
- keep = false
- break
- end
- end
- if keep then
- res.add(pd1)
- end
- end
- if res.is_empty then
- print "All lost! {candidates.join(", ")}"
- # FIXME: should be abort!
- end
- self.lookup_definitions_cache[mmodule, mtype] = res
- return res
+ return select_most_specific(mmodule, candidates)
end
private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
# If you want the really most specific property, then look at `lookup_next_definition`
#
# FIXME: Move to `MPropDef`?
- fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef]
+ fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
do
assert not mtype.need_anchor
if mtype isa MNullableType then mtype = mtype.mtype
# First, select all candidates
- var candidates = new Array[MPropDef]
+ var candidates = new Array[MPROPDEF]
for mpropdef in self.mpropdefs do
# If the definition is not imported by the module, then skip
if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
if candidates.length <= 1 then return candidates
# Second, filter the most specific ones
- var res = new Array[MPropDef]
+ return select_most_specific(mmodule, candidates)
+ end
+
+ # Return an array containing olny the most specific property definitions
+ # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
+ private fun select_most_specific(mmodule: MModule, candidates: Array[MPROPDEF]): Array[MPROPDEF]
+ do
+ var res = new Array[MPROPDEF]
for pd1 in candidates do
var cd1 = pd1.mclassdef
var c1 = cd1.mclass
var cd2 = pd2.mclassdef
var c2 = cd2.mclass
if c2.mclass_type == c1.mclass_type then
- if cd2.mmodule.in_importation <= cd1.mmodule then
+ if cd2.mmodule.in_importation < cd1.mmodule then
# cd2 refines cd1; therefore we skip pd1
keep = false
break
end
- else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
+ else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) and cd2.bound_mtype != cd1.bound_mtype then
# cd2 < cd1; therefore we skip pd1
keep = false
break
# REQUIRE: `mtype.has_mproperty(mmodule, self)`
fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF
do
+ assert mtype.has_mproperty(mmodule, self)
return lookup_all_definitions(mmodule, mtype).first
end
super
end
+ # Is the property defined at the top_level of the module?
+ # Currently such a property are stored in `Object`
+ var is_toplevel: Bool writable = false
+
# Is the property a constructor?
# Warning, this property can be inherited by subclasses with or without being a constructor
# therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
# Unlike `MProperty`, a `MPropDef` is a local definition that belong to a
# specific class definition (which belong to a specific module)
abstract class MPropDef
+ super MEntity
# The associated `MProperty` subclass.
# the two specialization hierarchy are symmetric
# The signature attached to the property definition
var msignature: nullable MSignature writable = null
- # The the method definition abstract?
+ # Is the method definition abstract?
var is_abstract: Bool writable = false
+
+ # Is the method definition intern?
+ var is_intern writable = false
+
+ # Is the method definition extern?
+ var is_extern writable = false
end
# A local definition of an attribute
self.to_s = s
self.need_init = need_init
end
+
+ # Can a class of kind `self` specializes a class of kine `other`?
+ fun can_specialize(other: MClassKind): Bool
+ do
+ if other == interface_kind then return true # everybody can specialize interfaces
+ if self == interface_kind or self == enum_kind then
+ # no other case for interfaces
+ return false
+ else if self == extern_kind then
+ # only compatible with themselve
+ return self == other
+ else if other == enum_kind or other == extern_kind then
+ # abstract_kind and concrete_kind are incompatible
+ return false
+ end
+ # remain only abstract_kind and concrete_kind
+ return true
+ end
end
fun abstract_kind: MClassKind do return once new MClassKind("abstract class", true)
fun concrete_kind: MClassKind do return once new MClassKind("class", true)
fun interface_kind: MClassKind do return once new MClassKind("interface", false)
fun enum_kind: MClassKind do return once new MClassKind("enum", false)
-fun extern_kind: MClassKind do return once new MClassKind("extern", false)
+fun extern_kind: MClassKind do return once new MClassKind("extern class", false)