# See the License for the specific language governing permissions and
# limitations under the License.
-# Object model of the Nit language
+# Classes, types and properties
#
-# This module define the entities of the Nit meta-model like modules,
-# classes, types and properties
-#
-# It also provide an API to build and query models.
-#
-# All model classes starts with the M letter (`MModule`, `MClass`, etc.)
-#
-# TODO: better doc
+# All three concepts are defined in this same module because these are strongly connected:
+# * types are based on classes
+# * classes contains properties
+# * some properties are types (virtual types)
#
# TODO: liearization, extern stuff
# FIXME: better handling of the types
module model
-import poset
-import location
import mmodule
import mdoc
+import ordered_tree
private import more_collections
redef class Model
# The only null type
var null_type: MNullType = new MNullType(self)
+
+ # Build an ordered tree with from `concerns`
+ fun concerns_tree(mconcerns: Collection[MConcern]): ConcernsTree do
+ var seen = new HashSet[MConcern]
+ var res = new ConcernsTree
+
+ var todo = new Array[MConcern]
+ todo.add_all mconcerns
+
+ while not todo.is_empty do
+ var c = todo.pop
+ if seen.has(c) then continue
+ var pc = c.parent_concern
+ if pc == null then
+ res.add(null, c)
+ else
+ res.add(pc, c)
+ todo.add(pc)
+ end
+ seen.add(c)
+ end
+
+ return res
+ end
+end
+
+# An OrderedTree that can be easily refined for display purposes
+class ConcernsTree
+ super OrderedTree[MConcern]
end
redef class MModule
private var object_type_cache: nullable MClassType
+ # The type `Pointer`, super class to all extern classes
+ var pointer_type: MClassType = self.get_primitive_class("Pointer").mclass_type is lazy
+
# The primitive type `Bool`
fun bool_type: MClassType
do
return get_primitive_class("Sys").mclass_type
end
+ fun finalizable_type: nullable MClassType
+ do
+ var clas = self.model.get_mclasses_by_name("Finalizable")
+ if clas == null then return null
+ return get_primitive_class("Finalizable").mclass_type
+ end
+
# Force to get the primitive class named `name` or abort
fun get_primitive_class(name: String): MClass
do
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
#
# This characteristic helps the reasoning about classes in a program since a
# single `MClass` object always denote the same class.
-# However, because a `MClass` is global, it does not really have properties nor
-# belong to a hierarchy since the property and the
-# hierarchy of a class depends of a module.
+#
+# The drawback is that classes (`MClass`) contain almost nothing by themselves.
+# These do not really have properties nor belong to a hierarchy since the property and the
+# hierarchy of a class depends of the refinement in the modules.
+#
+# Most services on classes require the precision of a module, and no one can asks what are
+# the super-classes of a class nor what are properties of a class without precising what is
+# the module considered.
+#
+# For instance, during the typing of a source-file, the module considered is the module of the file.
+# eg. the question *is the method `foo` exists in the class `Bar`?* must be reformulated into
+# *is the method `foo` exists in the class `Bar` in the current module?*
+#
+# During some global analysis, the module considered may be the main module of the program.
class MClass
super MEntity
# The short name of the class
# In Nit, the name of a class cannot evolve in refinements
- var name: String
+ redef var name: String
# The canonical name of the class
# Example: `"owner::module::MyClass"`
end
end
+ redef fun model do return intro_mmodule.model
+
# All class definitions (introduction and refinements)
var mclassdefs: Array[MClassDef] = new Array[MClassDef]
#
# A `MClassDef` is associated with an explicit (or almost) definition of a
# class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
-# a specific module
+# a specific class and a specific module, and contains declarations like super-classes
+# or properties.
+#
+# It is the class definitions that are the backbone of most things in the model:
+# ClassDefs are defined with regard with other classdefs.
+# Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
+#
+# Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
class MClassDef
super MEntity
self.to_s = "{mmodule}#{mclass}"
end
+ # Actually the name of the `mclass`
+ redef fun name do return mclass.name
+
+ redef fun model do return mmodule.model
+
# All declared super-types
# FIXME: quite ugly but not better idea yet
var supertypes: Array[MClassType] = new Array[MClassType]
abstract class MType
super MEntity
- # The model of the type
- fun model: Model is abstract
+ redef fun name do return to_s
# Return true if `self` is an subtype of `sup`.
# The typing is done using the standard typing policy of Nit.
# Replace formals generic types in self with resolved values in `mtype`
# If `cleanup_virtual` is true, then virtual types are also replaced
- # with their bounds
+ # with their bounds.
#
# This function returns self if `need_anchor` is false.
#
#
# The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
#
- # TODO: Explain the cleanup_virtual
- #
# FIXME: the parameter `cleanup_virtual` is just a bad idea, but having
# two function instead of one seems also to be a bad idea.
#
return res
end
+ # Return the not nullable version of the type
+ # Is the type is already not nullable, then self is returned.
+ #
+ # Note: this just remove the `nullable` notation, but the result can still contains null.
+ # For instance if `self isa MNullType` or self is a a formal type bounded by a nullable type.
+ fun as_notnullable: MType
+ do
+ return self
+ end
+
private var as_nullable_cache: nullable MType = null
abort
end
+ # Is the virtual type fixed for a given resolved_receiver?
+ fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool
+ do
+ assert not resolved_receiver.need_anchor
+ var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
+ if props.is_empty then
+ abort
+ end
+ for p in props do
+ if p.as(MVirtualTypeDef).is_fixed then return true
+ end
+ return false
+ end
+
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
assert can_resolve_for(mtype, anchor, mmodule)
if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
# If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
if res isa MVirtualType then return res
+ # If we are final, just return the resolution
+ if is_fixed(mmodule, resolved_reciever) then return res
# It the resolved type isa intern class, then there is no possible valid redefinition is any potentiel subclass. self is just fixed. so simply return the resolution
if res isa MClassType and res.mclass.kind == enum_kind then return res
# TODO: Add 'fixed' virtual type in the specification.
# The type associated the a formal parameter generic type of a class
#
# Each parameter type is associated to a specific class.
-# It's mean that all refinements of a same class "share" the parameter type,
-# but that a generic subclass has its on parameter types.
+# It means that all refinements of a same class "share" the parameter type,
+# but that a generic subclass has its own parameter types.
#
-# However, in the sense of the meta-model, the a parameter type of a class is
-# a valid types in a subclass. The "in the sense of the meta-model" is
+# However, in the sense of the meta-model, a parameter type of a class is
+# a valid type in a subclass. The "in the sense of the meta-model" is
# important because, in the Nit language, the programmer cannot refers
# directly to the parameter types of the super-classes.
#
#print "{class_name}: {self}/{mtype}/{anchor}?"
if mtype isa MGenericType and mtype.mclass == self.mclass then
- return mtype.arguments[self.rank]
+ var res = mtype.arguments[self.rank]
+ if anchor != null and res.need_anchor then
+ # Maybe the result can be resolved more if are bound to a final class
+ var r2 = res.anchor_to(mmodule, anchor)
+ if r2 isa MClassType and r2.mclass.kind == enum_kind then return r2
+ end
+ return res
end
# self is a parameter type of mtype (or of a super-class of mtype)
redef fun need_anchor do return mtype.need_anchor
redef fun as_nullable do return self
+ redef fun as_notnullable do return mtype
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
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
# A parameter in a signature
class MParameter
+ super MEntity
+
# The name of the parameter
- var name: String
+ redef var name: String
# The static type of the parameter
var mtype: MType
# Is the parameter a vararg?
var is_vararg: Bool
+ init(name: String, mtype: MType, is_vararg: Bool) do
+ self.name = name
+ self.mtype = mtype
+ self.is_vararg = is_vararg
+ end
+
+ 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
var res = new MParameter(self.name, newtype, self.is_vararg)
return res
end
+
+ redef fun model do return mtype.model
end
# A service (global property) that generalize method, attribute, etc.
var intro_mclassdef: MClassDef
# The (short) name of the property
- var name: String
+ redef var name: String
# The canonical name of the property
# Example: "owner::my_module::MyClass::my_method"
# associated definition, this method will abort
fun intro: MPROPDEF do return mpropdefs.first
+ redef fun model do return intro.model
+
# Alias for `name`
redef fun to_s do return name
fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
do
assert not mtype.need_anchor
- if mtype isa MNullableType then mtype = mtype.mtype
+ mtype = mtype.as_notnullable
var cache = self.lookup_definitions_cache[mmodule, mtype]
if cache != null then return cache
fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
do
assert not mtype.need_anchor
- if mtype isa MNullableType then mtype = mtype.mtype
+ mtype = mtype.as_notnullable
# First, select all candidates
var candidates = new Array[MPROPDEF]
fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
do
assert not mtype.need_anchor
- if mtype isa MNullableType then mtype = mtype.mtype
+ mtype = mtype.as_notnullable
var cache = self.lookup_all_definitions_cache[mmodule, mtype]
if cache != null then return cache
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 = false is writable
+
# 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
- var is_init: Bool writable = false
+ var is_init: Bool = false is writable
+
+ # The constructor is a (the) root init with empty signature but a set of initializers
+ var is_root_init: Bool = false is writable
# The the property a 'new' contructor?
- var is_new: Bool writable = false
+ var is_new: Bool = false is writable
# Is the property a legal constructor for a given class?
# As usual, visibility is not considered.
self.to_s = "{mclassdef}#{mproperty}"
end
+ # Actually the name of the `mproperty`
+ redef fun name do return mproperty.name
+
+ 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
end
# The signature attached to the property definition
- var msignature: nullable MSignature writable = null
+ 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]
- # The the method definition abstract?
- var is_abstract: Bool writable = false
+ # Is the method definition abstract?
+ var is_abstract: Bool = false is writable
+
+ # Is the method definition intern?
+ var is_intern = false is writable
+
+ # Is the method definition extern?
+ var is_extern = false is writable
end
# A local definition of an attribute
end
# The static type of the attribute
- var static_mtype: nullable MType writable = null
+ var static_mtype: nullable MType = null is writable
end
# A local definition of a virtual type
end
# The bound of the virtual type
- var bound: nullable MType writable = null
+ var bound: nullable MType = null is writable
+
+ # Is the bound fixed?
+ var is_fixed = false is writable
end
# A kind of class.
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)