v.assign(v.frame.returnvar.as(not null), res)
else if mpropdef == mwritepropdef then
assert arguments.length == 2
- v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
+ var recv = arguments.first
+ var arg = arguments[1]
+ if is_optional then
+ var value = v.new_var(self.mpropdef.static_mtype.as(not null))
+ v.add("if ({arg} == NULL) \{")
+ v.assign(value, evaluate_expr(v, recv))
+ v.add("\} else \{")
+ v.assign(value, arg)
+ v.add("\}")
+ arg = value
+ end
+ v.write_attribute(self.mpropdef.mproperty, arguments.first, arg)
if is_lazy then
var ret = self.mtype
var useiset = not ret.is_c_primitive and not ret isa MNullableType
noinit
readonly
writable
+optional
autoinit
noautoinit
lateinit
return evaluate_expr(v, recv, f)
else if mpropdef == mwritepropdef then
assert args.length == 2
- v.write_attribute(attr, recv, args[1])
+ var arg = args[1]
+ if is_optional and arg.mtype isa MNullType then
+ var f = v.new_frame(self, mpropdef, args)
+ arg = evaluate_expr(v, recv, f)
+ end
+ v.write_attribute(attr, recv, arg)
return null
else
abort
mreadpropdef.mproperty.is_autoinit = true
continue
end
- if npropdef.has_value then continue
- var paramname = mreadpropdef.mproperty.name
- var ret_type = msignature.return_mtype
- if ret_type == null then return
- var mparameter = new MParameter(paramname, ret_type, false)
- mparameters.add(mparameter)
+ if npropdef.has_value and not npropdef.is_optional then continue
var msetter = npropdef.mwritepropdef
if msetter == null then
# No setter, it is a readonly attribute, so just add it
+ var paramname = mreadpropdef.mproperty.name
+ var ret_type = msignature.return_mtype
+ if ret_type == null then return
+ var mparameter = new MParameter(paramname, ret_type, false)
+ mparameters.add(mparameter)
+
initializers.add(npropdef.mpropdef.mproperty)
npropdef.mpropdef.mproperty.is_autoinit = true
else
# Add the setter to the list
+ mparameters.add_all msetter.msignature.mparameters
initializers.add(msetter.mproperty)
msetter.mproperty.is_autoinit = true
end
# Is the node tagged lazy?
var is_lazy = false
+ # Is the node tagged optional?
+ var is_optional = false
+
# Has the node a default value?
# Could be through `n_expr` or `n_block`
var has_value = false
self.mlazypropdef = mlazypropdef
end
+ var atoptional = self.get_single_annotation("optional", modelbuilder)
+ if atoptional != null then
+ if not has_value then
+ modelbuilder.error(atoptional, "Error: `optional` attributes need a default value.")
+ end
+ is_optional = true
+ end
+
var atreadonly = self.get_single_annotation("readonly", modelbuilder)
if atreadonly != null then
if not has_value then
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, mtype, false)
+ var mparameter = new MParameter(name, mwritetype, false)
var msignature = new MSignature([mparameter], null)
mwritepropdef.msignature = msignature
end
end
return null # forward error
end
- self.error(nexpr, "Error: expected an expression.")
+ var more_message = null
+ var p = nexpr.parent
+ if p != null then more_message = p.bad_expr_message(nexpr)
+ if more_message == null then more_message = "" else more_message = " " + more_message
+ self.error(nexpr, "Error: expected an expression{more_message}.")
return null
end
redef class ANode
private fun accept_post_typing(v: TypeVisitor) do end
+
+ # An additional information message to explain the role of a child expression.
+ #
+ # The point of the method is to allow some kind of double dispatch so the parent
+ # choose how to describe its children.
+ private fun bad_expr_message(child: AExpr): nullable String do return null
end
redef class AAttrPropdef
# The property invoked by the send.
var callsite: nullable CallSite
+ redef fun bad_expr_message(child)
+ do
+ if child == self.n_expr then
+ return "to be the receiver of `{self.property_name}`"
+ end
+ return null
+ end
+
redef fun accept_typing(v)
do
var nrecv = self.n_expr
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class A
+ var i: Int = 99 is optional
+
+ var o: Object = 999 is optional
+end
+
+var a = new A
+a.i.output
+a.o.output
+
+a.i = 1
+a.o = 10
+a.i.output
+a.o.output
+
+a.i = null
+a.o = null
+a.i.output
+a.o.output
+
+a = new A(2)
+a.i.output
+a.o.output
+
+a = new A(3, true)
+a.i.output
+a.o.output
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import core::kernel
+
+redef class Int
+ fun a: Int do return 10*self+self.abs
+end
+
+fun foo(a: Int): Int do
+ a.output
+ return a
+end
+fun bar(a: Int) do a.output
+
+foo 1.a
+foo(1.a)
+foo (1).a
+foo(1).a
+foo((1).a)
+
+'\n'.output
+
+bar 1.a
+bar(1.a)
+#alt1#bar (1).a
+#alt1#bar(1).a
+bar((1).a)
--- /dev/null
+99
+999
+1
+10
+99
+999
+2
+999
+3
+true
-alt/base_meth_call_alt1.nit:36,1--6: Error: expected an expression.
+alt/base_meth_call_alt1.nit:36,1--6: Error: expected an expression to be the receiver of `output`.
--- /dev/null
+11
+11
+1
+1
+11
+
+11
+11
+11
--- /dev/null
+alt/error_arg_alt1.nit:37,1--7: Error: expected an expression to be the receiver of `a`.
+alt/error_arg_alt1.nit:38,1--6: Error: expected an expression to be the receiver of `a`.