modelize_property: Split model build of AAttrPropdef
authorFlorian Deljarry <deljarry.florian@gmail.com>
Fri, 31 Jan 2020 00:59:11 +0000 (19:59 -0500)
committerFlorian Deljarry <deljarry.florian@gmail.com>
Mon, 16 Mar 2020 19:07:05 +0000 (15:07 -0400)
Split the build method of AAttrPropdef

Signed-off-by: Florian Deljarry <deljarry.florian@gmail.com>

src/frontend/serialization_model_phase.nit
src/modelize/modelize_property.nit

index 7e9a506..a44833d 100644 (file)
@@ -267,8 +267,6 @@ redef init from_deserializer(v) do abort"""
 end
 
 redef class AAttrPropdef
-       private fun name: String do return n_id2.text
-
        # Name of this attribute in the serialized format
        private var serialize_name: String = name is lazy
 end
index beb9068..7aeffe8 100644 (file)
@@ -1181,6 +1181,10 @@ redef class AAttrPropdef
        # Could be through `n_expr`, `n_block` or `is_lazy`
        var has_value = false
 
+       # The name of the attribute
+       # Note: The name of the attribute is in reality the name of the mreadpropdef
+       var name: String = n_id2.text is lazy
+
        # The guard associated to a lazy attribute.
        # Because some engines does not have a working `isset`,
        # this additional attribute is used to guard the lazy initialization.
@@ -1195,48 +1199,14 @@ redef class AAttrPropdef
        redef fun build_property(modelbuilder, mclassdef)
        do
                var mclass = mclassdef.mclass
-               var nid2 = n_id2
-               var name = nid2.text
 
                var atabstract = self.get_single_annotation("abstract", modelbuilder)
-               if atabstract == null then
-                       if not mclass.kind.need_init then
-                               modelbuilder.error(self, "Error: attempt to define attribute `{name}` in the {mclass.kind} `{mclass}`.")
-                       end
 
-                       var mprop = new MAttribute(mclassdef, "_" + name, self.location, private_visibility)
-                       var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
-                       self.mpropdef = mpropdef
-                       modelbuilder.mpropdef2npropdef[mpropdef] = self
-               end
+               if atabstract == null then build_attribute_property(modelbuilder, mclassdef)
 
-               var readname = name
-               var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
-               if mreadprop == null then
-                       var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
-                       mreadprop = new MMethod(mclassdef, readname, self.location, mvisibility)
-                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then
-                               mreadprop.is_broken = true
-                               return
-                       end
-               else
-                       if mreadprop.is_broken then return
-                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return
-                       check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop)
-               end
-               mclassdef.mprop2npropdef[mreadprop] = self
-
-               var attr_mpropdef = mpropdef
-               if attr_mpropdef != null then
-                       mreadprop.getter_for = attr_mpropdef.mproperty
-                       attr_mpropdef.mproperty.getter = mreadprop
-               end
+               # Construction of the read property. If it's not correctly built just return.
+               if not build_read_property(modelbuilder, mclassdef) then return
 
-               var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
-               self.mreadpropdef = mreadpropdef
-               modelbuilder.mpropdef2npropdef[mreadpropdef] = self
-               set_doc(mreadpropdef, modelbuilder)
-               if mpropdef != null then mpropdef.mdoc = mreadpropdef.mdoc
                if atabstract != null then mreadpropdef.is_abstract = true
 
                has_value = n_expr != null or n_block != null
@@ -1259,29 +1229,8 @@ redef class AAttrPropdef
                        end
                end
 
-               var atlazy = self.get_single_annotation("lazy", modelbuilder)
-               var atlateinit = self.get_single_annotation("lateinit", modelbuilder)
-               if atlazy != null or atlateinit != null then
-                       if atlazy != null and atlateinit != null then
-                               modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.")
-                               return
-                       end
-                       if not has_value then
-                               if atlazy != null then
-                                       modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.")
-                               else if atlateinit != null then
-                                       modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.")
-                               end
-                               has_value = true
-                               return
-                       end
-                       is_lazy = true
-                       var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, self.location, none_visibility)
-                       mlazyprop.is_fictive = true
-                       var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location)
-                       mlazypropdef.is_fictive = true
-                       self.mlazypropdef = mlazypropdef
-               end
+               # Construction of the read property. If it's not correctly built just return.
+               if not build_lazy_property(modelbuilder, mclassdef) then return
 
                var atoptional = self.get_single_annotation("optional", modelbuilder)
                if atoptional != null then
@@ -1304,6 +1253,88 @@ redef class AAttrPropdef
                        modelbuilder.advice(self, "attr-in-refinement", "Warning: attributes in refinement need a value or `noautoinit`.")
                end
 
+               # Construction of the read property. If it's not correctly built just return.
+               if not build_write_property(modelbuilder, mclassdef, false) then return
+
+               if atabstract != null then mwritepropdef.is_abstract = true
+
+               var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
+               if atautoinit != null then
+                       if has_value then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.")
+                       else if not mwritepropdef.is_intro then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.")
+                       else if not mclassdef.is_intro then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.")
+                       else if atabstract == null then
+                               modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.")
+                       end
+               else if atabstract != null then
+                       # By default, abstract attribute are not autoinit
+                       noinit = true
+               end
+       end
+
+       # Build the attribute property
+       fun build_attribute_property(modelbuilder: ModelBuilder, mclassdef: MClassDef)
+       do
+               var mclass = mclassdef.mclass
+               var attribute_name = "_" + name
+
+               if not mclass.kind.need_init then
+                       modelbuilder.error(self, "Error: attempt to define attribute `{name}` in the {mclass.kind} `{mclass}`.")
+               end
+               var mprop = new MAttribute(mclassdef, "_" + name, self.location, private_visibility)
+               var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
+               self.mpropdef = mpropdef
+               modelbuilder.mpropdef2npropdef[mpropdef] = self
+       end
+
+       # Build the read method property to get the value of the attribute
+       # Return `true` if the property was correctly created else return `false`.
+       # Warning the signature of the property is not set. This step is done by `build_signature`.
+       fun build_read_property(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
+       do
+               var mclass = mclassdef.mclass
+
+               var readname = name
+               var mreadprop = modelbuilder.try_get_mproperty_by_name(self, mclassdef, readname).as(nullable MMethod)
+               if mreadprop == null then
+                       var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
+                       mreadprop = new MMethod(mclassdef, readname, self.location, mvisibility)
+                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then
+                               mreadprop.is_broken = true
+                               return false
+                       end
+               else
+                       if mreadprop.is_broken then return false
+                       if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return false
+                       check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop)
+               end
+               mclassdef.mprop2npropdef[mreadprop] = self
+
+               var attr_mpropdef = mpropdef
+               if attr_mpropdef != null then
+                       mreadprop.getter_for = attr_mpropdef.mproperty
+                       attr_mpropdef.mproperty.getter = mreadprop
+               end
+
+               var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
+               self.mreadpropdef = mreadpropdef
+               modelbuilder.mpropdef2npropdef[mreadpropdef] = self
+               set_doc(mreadpropdef, modelbuilder)
+               if mpropdef != null then mpropdef.mdoc = mreadpropdef.mdoc
+
+               return true
+       end
+
+       # Build the write method property to set the attribute value
+       # Return `true` if the property was correctly created else return `false`.
+       # Warning the signature of the property is not set.
+       fun build_write_property(modelbuilder: ModelBuilder, mclassdef: MClassDef, is_same_visibility: Bool): Bool
+       do
+               var mclass = mclassdef.mclass
+
                var writename = name + "="
                var atwritable = self.get_single_annotation("writable", modelbuilder)
                if atwritable != null then
@@ -1311,7 +1342,7 @@ redef class AAttrPropdef
                                writename = atwritable.arg_as_id(modelbuilder) or else writename
                        end
                end
-               var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, writename).as(nullable MMethod)
+               var mwriteprop = modelbuilder.try_get_mproperty_by_name(self, mclassdef, writename).as(nullable MMethod)
                var nwkwredef: nullable Token = null
                if atwritable != null then nwkwredef = atwritable.n_kwredef
                if mwriteprop == null then
@@ -1319,25 +1350,26 @@ redef class AAttrPropdef
                        if atwritable != null then
                                mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility)
                        else
-                               mvisibility = mreadprop.visibility
+                               mvisibility = mreadpropdef.mproperty.visibility
                                # By default, use protected visibility at most
-                               if mvisibility > protected_visibility then mvisibility = protected_visibility
+                               if mvisibility > protected_visibility and not is_same_visibility then mvisibility = protected_visibility
                        end
                        mwriteprop = new MMethod(mclassdef, writename, self.location, mvisibility)
                        if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then
                                mwriteprop.is_broken = true
-                               return
+                               return false
                        end
-                       mwriteprop.deprecation = mreadprop.deprecation
+                       mwriteprop.deprecation = mreadpropdef.mproperty.deprecation
                else
-                       if mwriteprop.is_broken then return
-                       if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return
+                       if mwriteprop.is_broken then return false
+                       if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return false
                        if atwritable != null then
                                check_redef_property_visibility(modelbuilder, atwritable.n_visibility, mwriteprop)
                        end
                end
                mclassdef.mprop2npropdef[mwriteprop] = self
 
+               var attr_mpropdef = mpropdef
                if attr_mpropdef != null then
                        mwriteprop.setter_for = attr_mpropdef.mproperty
                        attr_mpropdef.mproperty.setter = mwriteprop
@@ -1347,23 +1379,40 @@ redef class AAttrPropdef
                self.mwritepropdef = mwritepropdef
                modelbuilder.mpropdef2npropdef[mwritepropdef] = self
                mwritepropdef.mdoc = mreadpropdef.mdoc
-               if atabstract != null then mwritepropdef.is_abstract = true
 
-               var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
-               if atautoinit != null then
-                       if has_value then
-                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.")
-                       else if not mwritepropdef.is_intro then
-                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.")
-                       else if not mclassdef.is_intro then
-                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.")
-                       else if atabstract == null then
-                               modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.")
+               return true
+       end
+
+       # Build the lazy attribute property
+       # Return `true` if the property was correctly created else return `false`.
+       fun build_lazy_property(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
+       do
+               var mclass = mclassdef.mclass
+
+               var atlazy = self.get_single_annotation("lazy", modelbuilder)
+               var atlateinit = self.get_single_annotation("lateinit", modelbuilder)
+               if atlazy != null or atlateinit != null then
+                       if atlazy != null and atlateinit != null then
+                               modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.")
+                               return false
                        end
-               else if atabstract != null then
-                       # By default, abstract attribute are not autoinit
-                       noinit = true
+                       if not has_value then
+                               if atlazy != null then
+                                       modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.")
+                               else if atlateinit != null then
+                                       modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.")
+                               end
+                               has_value = true
+                               return false
+                       end
+                       is_lazy = true
+                       var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, self.location, none_visibility)
+                       mlazyprop.is_fictive = true
+                       var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location)
+                       mlazypropdef.is_fictive = true
+                       self.mlazypropdef = mlazypropdef
                end
+               return true
        end
 
        redef fun build_signature(modelbuilder)
@@ -1421,23 +1470,9 @@ redef class AAttrPropdef
                        mpropdef.static_mtype = mtype
                end
 
-               do
-                       var msignature = new MSignature(new Array[MParameter], mtype)
-                       mreadpropdef.msignature = msignature
-               end
+               build_read_signature
 
-               var mwritepropdef = self.mwritepropdef
-               if mwritepropdef != null then
-                       var mwritetype = mtype
-                       if is_optional then
-                               mwritetype = mwritetype.as_nullable
-                       end
-                       var name: String
-                       name = n_id2.text
-                       var mparameter = new MParameter(name, mwritetype, false)
-                       var msignature = new MSignature([mparameter], null)
-                       mwritepropdef.msignature = msignature
-               end
+               if self.mwritepropdef != null then build_write_signature
 
                var mlazypropdef = self.mlazypropdef
                if mlazypropdef != null then
@@ -1446,6 +1481,33 @@ redef class AAttrPropdef
                check_repeated_types(modelbuilder)
        end
 
+       # Build the read method signature
+       # `except`: mreadpropdef != null
+       # `expect`: mtype != null
+       fun build_read_signature
+       is
+               expect(mreadpropdef != null and mtype != null)
+       do
+               var msignature = new MSignature(new Array[MParameter], mtype)
+               mreadpropdef.msignature = msignature
+       end
+
+       # Build the write method signature
+       # `except`: mwritepropdef != null
+       # `expect`: mtype != null
+       fun build_write_signature
+       is
+               expect(mwritepropdef != null and mtype != null)
+       do
+               var mwritetype = mtype.as(not null)
+               if is_optional then
+                       mwritetype = mwritetype.as_nullable
+               end
+               var mparameter = new MParameter(name, mwritetype, false)
+               var msignature = new MSignature([mparameter], null)
+               mwritepropdef.msignature = msignature
+       end
+
        # Detect the static type from the value assigned to the attribute `self`
        #
        # Return the static type if it can be safely inferred.