Break closure must break. They are great for error management.
# The signature of the closure
readable attr _signature: MMSignature
+ # Is the closure a brek one
+ # aka is defined with the break keyword thus does not return
+ readable attr _is_break: Bool
+
# Adapt the signature to a different receiver
meth adaptation_to(r: MMType): MMClosure
do
- return new MMClosure(_signature.adaptation_to(r))
+ return new MMClosure(_signature.adaptation_to(r), _is_break)
end
- init(s: MMSignature)
+ init(s: MMSignature, is_break: Bool)
do
_signature = s
+ _is_break = is_break
end
meth not_for_self: MMClosure
do
- return new MMClosure(_signature.not_for_self)
+ return new MMClosure(_signature.not_for_self, _is_break)
end
end
end
end
+redef class AClosureCallExpr
+ redef meth accept_control_flow(v)
+ do
+ super
+ if variable.closure.is_break then v.control_flow_ctx.unreash = true
+ end
+end
+
redef class AIfExpr
redef meth accept_control_flow(v)
do
redef meth check_control_flow(v)
do
- if v.control_flow_ctx.unreash == false and closure.signature.return_type != null then
- v.error(self, "Control error: Reached end of bloc (a 'continue' with a value was expected).")
+ if v.control_flow_ctx.unreash == false then
+ if closure.signature.return_type != null then
+ v.error(self, "Control error: Reached end of bloc (a 'continue' with a value was expected).")
+ else if closure.is_break then
+ v.error(self, "Control error: Reached end of break bloc (a 'break' was expected).")
+ end
end
end
end
if sig == null then
sig = new MMSignature(new Array[MMType], null, v.local_class.get_type)
end
- var clos = new MMClosure(sig)
+ if sig.return_type != null and n_kwbreak != null then
+ v.error(self, "Syntax Error: A break bloc cannot have a return value.")
+ end
+ var clos = new MMClosure(sig, n_kwbreak != null)
v.signature_builder = old_signature_builder
old_signature_builder.closure_decls.add(self)
_variable = new ClosureVariable(n_id.to_symbol, self, clos)
# Block of the current method
readable writable attr _top_block: PExpr
- # Current closure 'return' static type (if any)
- readable writable attr _closure_stype: MMType
+ # Current closure (if any)
+ readable writable attr _closure: MMClosure
# Current closure method return type (for break) (if any)
readable writable attr _closure_break_stype: MMType = null
redef class AContinueExpr
redef meth after_typing(v)
do
- var t = v.closure_stype
+ var c = v.closure
+ var t: MMType = null
+ if c != null then
+ if c.is_break then
+ v.error(self, "Error: 'continue' forbiden in break blocks.")
+ return
+ end
+ t = c.signature.return_type
+ end
+
if n_expr == null and t != null then
v.error(self, "Error: continue with a value required in this bloc.")
else if n_expr != null and t == null then
closure = clos
- var old_stype = v.closure_stype
- v.closure_stype = sig.return_type
+ var old_clos = v.closure
+ v.closure = clos
v.variable_ctx = v.variable_ctx.sub
variables = new Array[AutoVariable]
_accept_typing2 = true
accept_typing(v)
- v.closure_stype = old_stype
+ v.closure = old_clos
end
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2009 Jean Privat <jean@pryen.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
+ meth foo
+ with break bar #!alt12#
+ #alt12#with break bar: Int
+ do
+ 1.output
+ bar #!alt1#
+ #alt2#bar(2)
+ #alt3#var x = bar
+ 4.output
+ end
+end
+
+meth work
+do
+ var a = new A
+ a.foo with do #!alt11#
+ #alt11#a.foo with x do
+ 2.output
+ #alt4#break
+ #alt5#break 'x'
+ #alt6#continue
+ #alt7#continue 'x'
+ #alt8#return
+ #alt9#return 'x'
+ 3.output
+ break #!alt13#
+ end
+ #alt10# a.foo
+ 5.output
+end
+
+0.output
+work
+6.output
+
--- /dev/null
+0
+1
+2
+3
+5
+6
--- /dev/null
+0
+1
+4
+5
+6
--- /dev/null
+alt/base_closure_break_alt10.nit:47,3--7: Error: property foo requires 1 blocs.
--- /dev/null
+alt/base_closure_break_alt11.nit:35,8--44:7: Error: 0 automatic variable names expected, 1 found.
--- /dev/null
+alt/base_closure_break_alt12.nit:21,3--21: Syntax Error: A break bloc cannot have a return value.
--- /dev/null
+alt/base_closure_break_alt13.nit:35,8--44:10: Control error: Reached end of break bloc (a 'break' was expected).
--- /dev/null
+alt/base_closure_break_alt2.nit:26,3--7: Error: 'bar' arity missmatch.
--- /dev/null
+alt/base_closure_break_alt3.nit:27,11--13: Type error: expected expression.
--- /dev/null
+0
+1
+2
+5
+6
--- /dev/null
+alt/base_closure_break_alt5.nit:39,3--11: Error: break without value required in this bloc.
--- /dev/null
+alt/base_closure_break_alt6.nit:40,3--10: Error: 'continue' forbiden in break blocks.
--- /dev/null
+alt/base_closure_break_alt7.nit:41,3--14: Error: 'continue' forbiden in break blocks.
--- /dev/null
+0
+1
+2
+6
--- /dev/null
+alt/base_closure_break_alt9.nit:43,3--12: Error: Return with value in a procedure.