Merge: add the annotation `readonly` on attributes
authorJean Privat <jean@pryen.org>
Tue, 22 Jul 2014 03:17:07 +0000 (23:17 -0400)
committerJean Privat <jean@pryen.org>
Tue, 22 Jul 2014 03:17:07 +0000 (23:17 -0400)
`readonly` just generate no setter. So the value must be set trough the initial value.

Basically it is like the Scala `val` keyword.
Note that unlike the Java `final` modifier, the value cannot be set in a constructor (use a private setter instead if you need a restriction on the setter visibility)

~~~.rb
class Toto
   var a = new Array[Int] is readonly
end
var t = new Toto
t.a.add 5 # OK
t.a = new Array[Int] # Error: no `a=` in Toto
~~~

Pull-Request: #604
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

1  2 
src/modelize_property.nit

@@@ -119,17 -119,8 +119,17 @@@ redef class ModelBuilde
                var mparameters = new Array[MParameter]
                var anode: nullable ANode = null
                for npropdef in nclassdef.n_propdefs do
 -                      if npropdef isa AAttrPropdef and npropdef.n_expr == null then
 +                      if npropdef isa AAttrPropdef then
                                if npropdef.mpropdef == null then return # Skip broken attribute
 +                              var at = npropdef.get_single_annotation("noinit", self)
 +                              if at != null then
 +                                      npropdef.noinit = true
 +                                      if npropdef.n_expr != null then
 +                                              self.error(at, "Error: `noinit` attributes cannot have an initial value")
 +                                      end
 +                                      continue # Skip noinit attributes
 +                              end
 +                              if npropdef.n_expr != null then continue
                                var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
                                var ret_type = npropdef.mpropdef.static_mtype
                                if ret_type == null then return
@@@ -642,9 -633,6 +642,9 @@@ en
  redef class AAttrPropdef
        redef type MPROPDEF: MAttributeDef
  
 +      # Is the node tagged `noinit`?
 +      var noinit = false
 +
        # The associated getter (read accessor) if any
        var mreadpropdef: nullable MMethodDef writable
        # The associated setter (write accessor) if any
                        modelbuilder.mpropdef2npropdef[mreadpropdef] = self
                        mreadpropdef.mdoc = mpropdef.mdoc
  
+                       var atreadonly = self.get_single_annotation("readonly", modelbuilder)
+                       if atreadonly != null then
+                               if n_expr == null then
+                                       modelbuilder.error(atreadonly, "Error: a readonly attribute needs a value")
+                               end
+                               # No setter, so just leave
+                               return
+                       end
                        var writename = name + "="
                        var nwritable = self.n_writable
 +                      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 nwkwredef: nullable Token = null
                        if nwritable != null then nwkwredef = nwritable.n_kwredef
 +                      if atwritable != null then nwkwredef = atwritable.n_kwredef
                        if mwriteprop == null then
                                var mvisibility
                                if nwritable != null then
                                        mvisibility = new_property_visibility(modelbuilder, mclassdef, nwritable.n_visibility)
 +                              else if atwritable != null then
 +                                      mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility)
                                else
                                        mvisibility = private_visibility
                                end
                                if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return
                                if nwritable != null then
                                        check_redef_property_visibility(modelbuilder, nwritable.n_visibility, mwriteprop)
 +                              else if atwritable != null then
 +                                      check_redef_property_visibility(modelbuilder, atwritable.n_visibility, mwriteprop)
                                end
                        end
                        mclassdef.mprop2npropdef[mwriteprop] = self