import ordered_tree
private import more_collections
+redef class MEntity
+ # The visibility of the MEntity.
+ #
+ # MPackages, MGroups and MModules are always public.
+ # The visibility of `MClass` and `MProperty` is defined by the keyword used.
+ # `MClassDef` and `MPropDef` return the visibility of `MClass` and `MProperty`.
+ fun visibility: MVisibility do return public_visibility
+end
+
redef class Model
# All known classes
var mclasses = new Array[MClass]
end
end
-# An OrderedTree that can be easily refined for display purposes
+# An OrderedTree bound to MEntity.
+#
+# We introduce a new class so it can be easily refined by tools working
+# with a Model.
+class MEntityTree
+ super OrderedTree[MEntity]
+end
+
+# A MEntityTree borned to MConcern.
+#
+# TODO remove when nitdoc is fully merged with model_collect
class ConcernsTree
super OrderedTree[MConcern]
end
if name == "Bool" and self.model.get_mclasses_by_name("Object") != null then
# Bool is injected because it is needed by engine to code the result
# of the implicit casts.
- var c = new MClass(self, name, null, enum_kind, public_visibility)
- var cladef = new MClassDef(self, c.mclass_type, new Location(null, 0,0,0,0))
+ var loc = model.no_location
+ var c = new MClass(self, name, loc, null, enum_kind, public_visibility)
+ var cladef = new MClassDef(self, c.mclass_type, loc)
cladef.set_supertypes([object_type])
cladef.add_in_hierarchy
return c
end
print("Fatal Error: no primitive class {name} in {self}")
exit(1)
+ abort
end
if cla.length != 1 then
var msg = "Fatal Error: more than one primitive class {name} in {self}:"
var props = self.model.get_mproperties_by_name(name)
if props == null then return null
var res: nullable MMethod = null
+ var recvtype = recv.intro.bound_mtype
for mprop in props do
assert mprop isa MMethod
- var intro = mprop.intro_mclassdef
- for mclassdef in recv.mclassdefs do
- if not self.in_importation.greaters.has(mclassdef.mmodule) then continue
- if not mclassdef.in_hierarchy.greaters.has(intro) then continue
- if res == null then
- res = mprop
- else if res != mprop then
- print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
- abort
- end
+ if not recvtype.has_mproperty(self, mprop) then continue
+ if res == null then
+ res = mprop
+ else if res != mprop then
+ print("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
+ abort
end
end
return res
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
+ # the introducing module is used for naming and visibility.
var intro_mmodule: MModule
# The short name of the class
# In Nit, the name of a class cannot evolve in refinements
- redef var name: String
+ redef var name
+
+ redef var location
# The canonical name of the class
#
# The visibility of the class
# In Nit, the visibility of a class cannot evolve in refinements
- var visibility: MVisibility
+ redef var visibility
init
do
# The principal static type of the class.
#
- # For non-generic class, mclass_type is the only `MClassType` based
+ # For non-generic class, `mclass_type` is the only `MClassType` based
# on self.
#
# For a generic class, the arguments are the formal parameters.
- # i.e.: for the class Array[E:Object], the `mclass_type` is Array[E].
- # If you want Array[Object] the see `MClassDef::bound_mtype`
+ # i.e.: for the class `Array[E:Object]`, the `mclass_type` is `Array[E]`.
+ # If you want `Array[Object]`, see `MClassDef::bound_mtype`.
#
# For generic classes, the mclass_type is also the way to get a formal
# generic parameter type.
# Is `self` and abstract class?
var is_abstract: Bool is lazy do return kind == abstract_kind
+
+ redef fun mdoc_or_fallback do return intro.mdoc_or_fallback
end
# ENSURE: `bound_mtype.mclass == self.mclass`
var bound_mtype: MClassType
- # The origin of the definition
- var location: Location
+ redef var location: Location
+
+ redef fun visibility do return mclass.visibility
# Internal name combining the module and the class
- # Example: "mymodule#MyClass"
- redef var to_s: String is noinit
+ # Example: "mymodule$MyClass"
+ redef var to_s is noinit
init
do
assert not isset mclass._intro
mclass.intro = self
end
- self.to_s = "{mmodule}#{mclass}"
+ self.to_s = "{mmodule}${mclass}"
end
# Actually the name of the `mclass`
redef fun name do return mclass.name
- # The module and class name separated by a '#'.
+ # The module and class name separated by a '$'.
#
# The short-name of the class is used for introduction.
- # Example: "my_module#MyClass"
+ # Example: "my_module$MyClass"
#
# The full-name of the class is used for refinement.
- # Example: "my_module#intro_module::MyClass"
+ # Example: "my_module$intro_module::MyClass"
redef var full_name is lazy do
if is_intro then
- # public gives 'p#A'
- # private gives 'p::m#A'
- return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}"
- else if mclass.intro_mmodule.mproject != mmodule.mproject then
- # public gives 'q::n#p::A'
- # private gives 'q::n#p::m::A'
- return "{mmodule.full_name}#{mclass.full_name}"
+ # public gives 'p$A'
+ # private gives 'p::m$A'
+ return "{mmodule.namespace_for(mclass.visibility)}${mclass.name}"
+ else if mclass.intro_mmodule.mpackage != mmodule.mpackage then
+ # public gives 'q::n$p::A'
+ # private gives 'q::n$p::m::A'
+ return "{mmodule.full_name}${mclass.full_name}"
else if mclass.visibility > private_visibility then
- # public gives 'p::n#A'
- return "{mmodule.full_name}#{mclass.name}"
+ # public gives 'p::n$A'
+ return "{mmodule.full_name}${mclass.name}"
else
- # private gives 'p::n#::m::A' (redundant p is omitted)
- return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}"
+ # private gives 'p::n$::m::A' (redundant p is omitted)
+ return "{mmodule.full_name}$::{mclass.intro_mmodule.name}::{mclass.name}"
end
end
redef var c_name is lazy do
if is_intro then
return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}"
- else if mclass.intro_mmodule.mproject == mmodule.mproject and mclass.visibility > private_visibility then
+ else if mclass.intro_mmodule.mpackage == mmodule.mpackage and mclass.visibility > private_visibility then
return "{mmodule.c_name}___{mclass.name.to_cmangle}"
else
return "{mmodule.c_name}___{mclass.c_name}"
# All property definitions in the class (introductions and redefinitions)
var mpropdefs = new Array[MPropDef]
+
+ # The special autoinit constructor
+ var auto_init: nullable MMethodDef = null is writable
end
# A global static type
end
#print "4.is {sub} a {sup}? <- no more resolution"
- assert sub isa MClassType else print "{sub} <? {sub}" # It is the only remaining type
-
- # A unfixed formal type can only accept itself
- if sup isa MFormalType then
- return false
+ if sub isa MBottomType then
+ return true
end
- if sup isa MNullType then
- # `sup` accepts only null
+ assert sub isa MClassType else print "{sub} <? {sub}" # It is the only remaining type
+
+ # Handle sup-type when the sub-type is class-based (other cases must have be identified before).
+ if sup isa MFormalType or sup isa MNullType or sup isa MBottomType then
+ # These types are not super-types of Class-based types.
return false
end
- assert sup isa MClassType # It is the only remaining type
+ assert sup isa MClassType else print "got {sup} {sub.inspect}" # It is the only remaining type
# Now both are MClassType, we need to dig
# The result is returned exactly as declared in the "type" property (verbatim).
# So it could be another formal type.
#
- # In case of conflict, the method aborts.
+ # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`.
fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self
# Resolve the formal type to its simplest equivalent form.
#
# By default, return self.
# See the redefinitions for specific behavior in each kind of type.
+ #
+ # In case of conflicts or inconsistencies in the model, the method returns a `MBottomType`.
fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self
# Can the type be resolved?
redef fun model do return self.mclass.intro_mmodule.model
+ redef fun location do return mclass.location
+
# TODO: private init because strongly bounded to its mclass. see `mclass.mclass_type`
# The formal arguments of the type
# The short-name of the class, then the full-name of each type arguments within brackets.
# Example: `"Map[String, List[Int]]"`
- redef var to_s: String is noinit
+ redef var to_s is noinit
# The full-name of the class, then the full-name of each type arguments within brackets.
- # Example: `"standard::Map[standard::String, standard::List[standard::Int]]"`
+ # Example: `"core::Map[core::String, core::List[core::Int]]"`
redef var full_name is lazy do
var args = new Array[String]
for t in arguments do
return res.to_s
end
- redef var need_anchor: Bool is noinit
+ redef var need_anchor is noinit
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
# Its the definitions of this property that determine the bound or the virtual type.
var mproperty: MVirtualTypeProp
+ redef fun location do return mproperty.location
+
redef fun model do return self.mproperty.intro_mclassdef.mmodule.model
redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
do
- return lookup_single_definition(mmodule, resolved_receiver).bound.as(not null)
+ return lookup_single_definition(mmodule, resolved_receiver).bound or else new MBottomType(model)
end
private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef
assert resolved_receiver isa MClassType # It is the only remaining type
var prop = lookup_single_definition(mmodule, resolved_receiver)
- var res = prop.bound.as(not null)
+ var res = prop.bound
+ if res == null then return new MBottomType(model)
# Recursively lookup the fixed result
res = res.lookup_fixed(mmodule, resolved_receiver)
redef fun model do return self.mclass.intro_mmodule.model
+ redef fun location do return mclass.location
+
# The position of the parameter (0 for the first parameter)
# FIXME: is `position` a better name?
var rank: Int
end
if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
if resolved_receiver isa MParameterType then
+ assert anchor != null
assert resolved_receiver.mclass == anchor.mclass
resolved_receiver = anchor.arguments[resolved_receiver.rank]
if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
# The base type
var mtype: MType
+ redef fun location do return mtype.location
+
redef fun model do return self.mtype.model
redef fun need_anchor do return mtype.need_anchor
redef fun as_nullable do return mtype.as_nullable
self.to_s = "nullable {mtype}"
end
- redef var to_s: String is noinit
+ redef var to_s is noinit
redef var full_name is lazy do return "nullable {mtype.full_name}"
# The is only one null type per model, see `MModel::null_type`.
class MNullType
super MType
- redef var model: Model
+ redef var model
redef fun to_s do return "null"
redef fun full_name do return "null"
redef fun c_name do return "null"
# Semantically it is the singleton `null.as_notnull`.
class MBottomType
super MType
- redef var model: Model
+ redef var model
redef fun to_s do return "bottom"
redef fun full_name do return "bottom"
redef fun c_name do return "bottom"
for i in [0..mparameters.length[ do
var parameter = mparameters[i]
if parameter.is_vararg then
- assert vararg_rank == -1
+ if vararg_rank >= 0 then
+ # If there is more than one vararg,
+ # consider that additional arguments cannot be mapped.
+ vararg_rank = -1
+ break
+ end
vararg_rank = i
end
end
self.vararg_rank = vararg_rank
end
- # The rank of the ellipsis (`...`) for vararg (starting from 0).
+ # The rank of the main ellipsis (`...`) for vararg (starting from 0).
# value is -1 if there is no vararg.
# Example: for "(a: Int, b: Bool..., c: Char)" #-> vararg_rank=1
+ #
+ # From a model POV, a signature can contain more than one vararg parameter,
+ # the `vararg_rank` just indicates the one that will receive the additional arguments.
+ # However, currently, if there is more that one vararg parameter, no one will be the main one,
+ # and additional arguments will be refused.
var vararg_rank: Int is noinit
# The number of parameters
super MEntity
# The name of the parameter
- redef var name: String
+ redef var name
# The static type of the parameter
var mtype: MType
var intro_mclassdef: MClassDef
# The (short) name of the property
- redef var name: String
+ redef var name
+
+ redef var location
+
+ redef fun mdoc_or_fallback do return intro.mdoc_or_fallback
# The canonical name of the property.
#
- # It is the short-`name` prefixed by the short-name of the class and the full-name of the module.
- # Example: "my_project::my_module::MyClass::my_method"
+ # It is currently the short-`name` prefixed by the short-name of the class and the full-name of the module.
+ # Example: "my_package::my_module::MyClass::my_method"
+ #
+ # The full-name of the module is needed because two distinct modules of the same package can
+ # still refine the same class and introduce homonym properties.
+ #
+ # For public properties not introduced by refinement, the module name is not used.
+ #
+ # Example: `my_package::MyClass::My_method`
redef var full_name is lazy do
- return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
+ if intro_mclassdef.is_intro then
+ return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}"
+ else
+ return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}"
+ end
end
redef var c_name is lazy do
end
# The visibility of the property
- var visibility: MVisibility
+ redef var visibility
# Is the property usable as an initializer?
var is_autoinit = false is writable
# The associated global property
var mproperty: MPROPERTY
- # The origin of the definition
- var location: Location
+ redef var location: Location
+
+ redef fun visibility do return mproperty.visibility
init
do
assert not isset mproperty._intro
mproperty.intro = self
end
- self.to_s = "{mclassdef}#{mproperty}"
+ self.to_s = "{mclassdef}${mproperty}"
end
# Actually the name of the `mproperty`
# * a property "p::m::A::x"
# * redefined in a refinement of a class "q::n::B"
# * in a module "r::o"
- # * so "r::o#q::n::B#p::m::A::x"
+ # * so "r::o$q::n::B$p::m::A::x"
#
# Fortunately, the full-name is simplified when entities are repeated.
- # For the previous case, the simplest form is "p#A#x".
+ # For the previous case, the simplest form is "p$A$x".
redef var full_name is lazy do
var res = new FlatBuffer
- # The first part is the mclassdef. Worst case is "r::o#q::n::B"
+ # The first part is the mclassdef. Worst case is "r::o$q::n::B"
res.append mclassdef.full_name
- res.append "#"
+ res.append "$"
if mclassdef.mclass == mproperty.intro_mclassdef.mclass then
# intro are unambiguous in a class
res.append name
else
# Just try to simplify each part
- if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then
+ if mclassdef.mmodule.mpackage != mproperty.intro_mclassdef.mmodule.mpackage then
# precise "p::m" only if "p" != "r"
- res.append mproperty.intro_mclassdef.mmodule.full_name
+ res.append mproperty.intro_mclassdef.mmodule.namespace_for(mproperty.visibility)
res.append "::"
else if mproperty.visibility <= private_visibility then
- # Same project ("p"=="q"), but private visibility,
+ # Same package ("p"=="q"), but private visibility,
# does the module part ("::m") need to be displayed
- if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mproject then
+ if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mpackage then
res.append "::"
res.append mproperty.intro_mclassdef.mmodule.name
res.append "::"
redef fun model do return mclassdef.model
# Internal name combining the module, the class and the property
- # Example: "mymodule#MyClass#mymethod"
- redef var to_s: String is noinit
+ # Example: "mymodule$MyClass$mymethod"
+ redef var to_s is noinit
# Is self the definition that introduce the property?
- fun is_intro: Bool do return mproperty.intro == self
+ fun is_intro: Bool do return isset mproperty._intro and mproperty.intro == self
# Return the next definition in linearization of `mtype`.
#
# The signature attached to the property definition
var msignature: nullable MSignature = null is writable
- # The signature attached to the `new` call on a root-init
- # This is a concatenation of the signatures of the initializers
- #
- # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
- var new_msignature: nullable MSignature = null is writable
-
# List of initialisers to call in root-inits
#
# They could be setters or attributes
- #
- # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
var initializers = new Array[MProperty]
+ # Does the method take the responsibility to call `init`?
+ #
+ # If the method is used as an initializer, then
+ # using this information prevents to call `init` twice.
+ var is_calling_init = false is writable
+
# Is the method definition abstract?
var is_abstract: Bool = false is writable
# Note this class is basically an enum.
# FIXME: use a real enum once user-defined enums are available
class MClassKind
- redef var to_s: String
+ redef var to_s
# Is a constructor required?
var need_init: Bool