From: Jean Privat Date: Thu, 22 Jan 2009 20:59:26 +0000 (-0500) Subject: Add break closure. X-Git-Tag: mercurial_tip~17 X-Git-Url: http://nitlanguage.org Add break closure. Break closure must break. They are great for error management. --- diff --git a/src/metamodel/static_type.nit b/src/metamodel/static_type.nit index 2e439d0..245d0a7 100644 --- a/src/metamodel/static_type.nit +++ b/src/metamodel/static_type.nit @@ -220,20 +220,25 @@ class MMClosure # 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 diff --git a/src/syntax/control_flow.nit b/src/syntax/control_flow.nit index f95adf1..5f9b1f2 100644 --- a/src/syntax/control_flow.nit +++ b/src/syntax/control_flow.nit @@ -216,6 +216,14 @@ redef class AAbortExpr 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 @@ -318,8 +326,12 @@ special AControlableBlock 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 diff --git a/src/syntax/mmbuilder.nit b/src/syntax/mmbuilder.nit index 85aa9ec..6a03fde 100644 --- a/src/syntax/mmbuilder.nit +++ b/src/syntax/mmbuilder.nit @@ -1179,7 +1179,10 @@ redef class AClosureDecl 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) diff --git a/src/syntax/typing.nit b/src/syntax/typing.nit index e784269..ed9d8e7 100644 --- a/src/syntax/typing.nit +++ b/src/syntax/typing.nit @@ -50,8 +50,8 @@ special AbsSyntaxVisitor # 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 @@ -376,7 +376,16 @@ end 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 @@ -1288,8 +1297,8 @@ redef class AClosureDef 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] @@ -1303,7 +1312,7 @@ redef class AClosureDef _accept_typing2 = true accept_typing(v) - v.closure_stype = old_stype + v.closure = old_clos end end diff --git a/tests/base_closure_break.nit b/tests/base_closure_break.nit new file mode 100644 index 0000000..814cf7a --- /dev/null +++ b/tests/base_closure_break.nit @@ -0,0 +1,54 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2009 Jean Privat +# +# 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 + diff --git a/tests/sav/base_closure_break.sav b/tests/sav/base_closure_break.sav new file mode 100644 index 0000000..6196664 --- /dev/null +++ b/tests/sav/base_closure_break.sav @@ -0,0 +1,6 @@ +0 +1 +2 +3 +5 +6 diff --git a/tests/sav/base_closure_break_alt1.sav b/tests/sav/base_closure_break_alt1.sav new file mode 100644 index 0000000..5ac6b87 --- /dev/null +++ b/tests/sav/base_closure_break_alt1.sav @@ -0,0 +1,5 @@ +0 +1 +4 +5 +6 diff --git a/tests/sav/base_closure_break_alt10.sav b/tests/sav/base_closure_break_alt10.sav new file mode 100644 index 0000000..291fd47 --- /dev/null +++ b/tests/sav/base_closure_break_alt10.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt10.nit:47,3--7: Error: property foo requires 1 blocs. diff --git a/tests/sav/base_closure_break_alt11.sav b/tests/sav/base_closure_break_alt11.sav new file mode 100644 index 0000000..892cd56 --- /dev/null +++ b/tests/sav/base_closure_break_alt11.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt11.nit:35,8--44:7: Error: 0 automatic variable names expected, 1 found. diff --git a/tests/sav/base_closure_break_alt12.sav b/tests/sav/base_closure_break_alt12.sav new file mode 100644 index 0000000..a05024b --- /dev/null +++ b/tests/sav/base_closure_break_alt12.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt12.nit:21,3--21: Syntax Error: A break bloc cannot have a return value. diff --git a/tests/sav/base_closure_break_alt13.sav b/tests/sav/base_closure_break_alt13.sav new file mode 100644 index 0000000..4bfc47b --- /dev/null +++ b/tests/sav/base_closure_break_alt13.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt13.nit:35,8--44:10: Control error: Reached end of break bloc (a 'break' was expected). diff --git a/tests/sav/base_closure_break_alt2.sav b/tests/sav/base_closure_break_alt2.sav new file mode 100644 index 0000000..fc39a6c --- /dev/null +++ b/tests/sav/base_closure_break_alt2.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt2.nit:26,3--7: Error: 'bar' arity missmatch. diff --git a/tests/sav/base_closure_break_alt3.sav b/tests/sav/base_closure_break_alt3.sav new file mode 100644 index 0000000..5d74e3d --- /dev/null +++ b/tests/sav/base_closure_break_alt3.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt3.nit:27,11--13: Type error: expected expression. diff --git a/tests/sav/base_closure_break_alt4.sav b/tests/sav/base_closure_break_alt4.sav new file mode 100644 index 0000000..fb8d875 --- /dev/null +++ b/tests/sav/base_closure_break_alt4.sav @@ -0,0 +1,5 @@ +0 +1 +2 +5 +6 diff --git a/tests/sav/base_closure_break_alt5.sav b/tests/sav/base_closure_break_alt5.sav new file mode 100644 index 0000000..68c0573 --- /dev/null +++ b/tests/sav/base_closure_break_alt5.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt5.nit:39,3--11: Error: break without value required in this bloc. diff --git a/tests/sav/base_closure_break_alt6.sav b/tests/sav/base_closure_break_alt6.sav new file mode 100644 index 0000000..80d327a --- /dev/null +++ b/tests/sav/base_closure_break_alt6.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt6.nit:40,3--10: Error: 'continue' forbiden in break blocks. diff --git a/tests/sav/base_closure_break_alt7.sav b/tests/sav/base_closure_break_alt7.sav new file mode 100644 index 0000000..4cf1e7c --- /dev/null +++ b/tests/sav/base_closure_break_alt7.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt7.nit:41,3--14: Error: 'continue' forbiden in break blocks. diff --git a/tests/sav/base_closure_break_alt8.sav b/tests/sav/base_closure_break_alt8.sav new file mode 100644 index 0000000..f9c3b7b --- /dev/null +++ b/tests/sav/base_closure_break_alt8.sav @@ -0,0 +1,4 @@ +0 +1 +2 +6 diff --git a/tests/sav/base_closure_break_alt9.sav b/tests/sav/base_closure_break_alt9.sav new file mode 100644 index 0000000..6b7c8ef --- /dev/null +++ b/tests/sav/base_closure_break_alt9.sav @@ -0,0 +1 @@ +alt/base_closure_break_alt9.nit:43,3--12: Error: Return with value in a procedure.