Skip to content

Commit

Permalink
Merge: modelize_property: Split the build_property method of AAttrPro…
Browse files Browse the repository at this point in the history
…pdef

This pr split the `build property` method into several methods. The objective is to be able to build the entities of the model (read, write...) more independently according to the current state. The construction of the signature was also split for the same purpose.

Pull-Request: #2813
Reviewed-by: Jean Privat <[email protected]>
  • Loading branch information
privat committed Mar 17, 2020
2 parents 22fd41c + 0bf1b73 commit 3c92d1e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 99 deletions.
2 changes: 0 additions & 2 deletions src/frontend/serialization_model_phase.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
256 changes: 159 additions & 97 deletions src/modelize/modelize_property.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -1304,40 +1253,123 @@ 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
if not atwritable.n_args.is_empty then
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
var mvisibility
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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down

0 comments on commit 3c92d1e

Please sign in to comment.