- # Visit the AST and create the MClass objects
- private fun build_a_mclass(nmodule: AModule, nclassdef: AClassdef)
- do
- var mmodule = nmodule.mmodule.as(not null)
-
- var name: String
- var nkind: nullable AClasskind
- var mkind: MClassKind
- var nvisibility: nullable AVisibility
- var mvisibility: nullable MVisibility
- var arity = 0
- if nclassdef isa AStdClassdef then
- name = nclassdef.n_id.text
- nkind = nclassdef.n_classkind
- mkind = nkind.mkind
- nvisibility = nclassdef.n_visibility
- mvisibility = nvisibility.mvisibility
- arity = nclassdef.n_formaldefs.length
- else if nclassdef isa ATopClassdef then
- name = "Object"
- nkind = null
- mkind = interface_kind
- nvisibility = null
- mvisibility = public_visibility
- else if nclassdef isa AMainClassdef then
- name = "Sys"
- nkind = null
- mkind = concrete_kind
- nvisibility = null
- mvisibility = public_visibility
- else
- abort
- end
-
- var mclass = try_get_mclass_by_name(nclassdef, mmodule, name)
- if mclass == null then
- mclass = new MClass(mmodule, name, arity, mkind, mvisibility)
- #print "new class {mclass}"
- else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
- error(nclassdef, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
- return
- else if nclassdef isa AStdClassdef and nclassdef.n_kwredef == null then
- error(nclassdef, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
- return
- else if mclass.arity != arity then
- error(nclassdef, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
- return
- else if nkind != null and mkind != concrete_kind and mclass.kind != mkind then
- error(nkind, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
- else if nvisibility != null and mvisibility != public_visibility and mclass.visibility != mvisibility then
- error(nvisibility, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
- end
- nclassdef.mclass = mclass
- nmodule.mclass2nclassdef[mclass] = nclassdef
- end
-
- # Visit the AST and create the MClassDef objects
- private fun build_a_mclassdef(nmodule: AModule, nclassdef: AClassdef)
- do
- var mmodule = nmodule.mmodule.as(not null)
- var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
- var mclass = nclassdef.mclass
- if mclass == null then return # Skip error
- #var mclassdef = nclassdef.mclassdef.as(not null)
-
- var names = new Array[String]
- var bounds = new Array[MType]
- if nclassdef isa AStdClassdef and mclass.arity > 0 then
- # Collect formal parameter names
- for i in [0..mclass.arity[ do
- var nfd = nclassdef.n_formaldefs[i]
- var ptname = nfd.n_id.text
- if names.has(ptname) then
- error(nfd, "Error: A formal parameter type `{ptname}' already exists")
- return
- end
- names.add(ptname)
- end
-
- # Revolve bound for formal parameter names
- for i in [0..mclass.arity[ do
- var nfd = nclassdef.n_formaldefs[i]
- var nfdt = nfd.n_type
- if nfdt != null then
- var bound = resolve_mtype_unchecked(nclassdef, nfdt, false)
- if bound == null then return # Forward error
- if bound.need_anchor then
- # No F-bounds!
- error(nfd, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
- else
- bounds.add(bound)
- end
- else if mclass.mclassdefs.is_empty then
- # No bound, then implicitely bound by nullable Object
- bounds.add(objectclass.mclass_type.as_nullable)
- else
- # Inherit the bound
- bounds.add(mclass.intro.bound_mtype.arguments[i])
- end
- end
- end
-
- var bound_mtype = mclass.get_mtype(bounds)
- var mclassdef = new MClassDef(mmodule, bound_mtype, nclassdef.location, names)
- nclassdef.mclassdef = mclassdef
- self.mclassdef2nclassdef[mclassdef] = nclassdef
-
- if mclassdef.is_intro then
- self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
- else
- self.toolcontext.info("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
- end
- end
-
- # Visit the AST and set the super-types of the MClassdef objects
- private fun collect_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
- do
- var mmodule = nmodule.mmodule.as(not null)
- var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
- var mclass = nclassdef.mclass.as(not null)
- var mclassdef = nclassdef.mclassdef.as(not null)
-
- var specobject = true
- var supertypes = new Array[MClassType]
- if nclassdef isa AStdClassdef then
- for nsc in nclassdef.n_superclasses do
- specobject = false
- var ntype = nsc.n_type
- var mtype = resolve_mtype_unchecked(nclassdef, ntype, false)
- if mtype == null then continue # Skip because of error
- if not mtype isa MClassType then
- error(ntype, "Error: supertypes cannot be a formal type")
- return
- end
- supertypes.add mtype
- #print "new super : {mclass} < {mtype}"
- end
- end
- if specobject and mclass.name != "Object" and objectclass != null and mclassdef.is_intro then
- supertypes.add objectclass.mclass_type
- end
-
- mclassdef.set_supertypes(supertypes)
- if not supertypes.is_empty then self.toolcontext.info("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
- end
-
- # Check the validity of the specialization heirarchy
- private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
- do
- var mmodule = nmodule.mmodule.as(not null)
- var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
- var mclass = nclassdef.mclass.as(not null)
- var mclassdef = nclassdef.mclassdef.as(not null)
-
- for s in mclassdef.supertypes do
- if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then
- error(nclassdef, "Error: Inheritance loop for class {mclass} with type {s}")
- end
- end
- end
-
- # Build the classes of the module `nmodule'.
- # REQUIRE: classes of imported modules are already build. (let `phase' do the job)
- private fun build_classes(nmodule: AModule)
- do
- # Force building recursively
- if nmodule.build_classes_is_done then return
- nmodule.build_classes_is_done = true
- var mmodule = nmodule.mmodule.as(not null)
- for imp in mmodule.in_importation.direct_greaters do
-
- build_classes(mmodule2nmodule[imp])
- end
-
- # Create all classes
- for nclassdef in nmodule.n_classdefs do
- self.build_a_mclass(nmodule, nclassdef)
- end
-
- # Create all classdefs
- for nclassdef in nmodule.n_classdefs do
- self.build_a_mclassdef(nmodule, nclassdef)
- end
-
- for nclassdef in nmodule.n_classdefs do
- if nclassdef.mclassdef == null then return # forward error
- end
-
- # Create inheritance on all classdefs
- for nclassdef in nmodule.n_classdefs do
- self.collect_a_mclassdef_inheritance(nmodule, nclassdef)
- end
-
- # Create the mclassdef hierarchy
- for nclassdef in nmodule.n_classdefs do
- var mclassdef = nclassdef.mclassdef.as(not null)
- mclassdef.add_in_hierarchy
- end
-
- # Check inheritance
- for nclassdef in nmodule.n_classdefs do
- self.check_supertypes(nmodule, nclassdef)
- end
-
- # Check unchecked ntypes
- for nclassdef in nmodule.n_classdefs do
- if nclassdef isa AStdClassdef then
- # check bound of formal parameter
- for nfd in nclassdef.n_formaldefs do
- var nfdt = nfd.n_type
- if nfdt != null and nfdt.mtype != null then
- var bound = resolve_mtype(nclassdef, nfdt)
- if bound == null then return # Forward error
- end
- end
- # check declared super types
- for nsc in nclassdef.n_superclasses do
- var ntype = nsc.n_type
- if ntype.mtype != null then
- var mtype = resolve_mtype(nclassdef, ntype)
- if mtype == null then return # Forward error
- end
- end
- end
-
- end
-
- # TODO: Check that the super-class is not intrusive
-
- # TODO: Check that the super-class is not already known (by transitivity)
- end
-