Add break closure.
authorJean Privat <jean@pryen.org>
Thu, 22 Jan 2009 20:59:26 +0000 (15:59 -0500)
committerJean Privat <jean@pryen.org>
Thu, 22 Jan 2009 20:59:26 +0000 (15:59 -0500)
Break closure must break. They are great for error management.

19 files changed:
src/metamodel/static_type.nit
src/syntax/control_flow.nit
src/syntax/mmbuilder.nit
src/syntax/typing.nit
tests/base_closure_break.nit [new file with mode: 0644]
tests/sav/base_closure_break.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt1.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt10.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt11.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt12.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt13.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt2.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt3.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt4.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt5.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt6.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt7.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt8.sav [new file with mode: 0644]
tests/sav/base_closure_break_alt9.sav [new file with mode: 0644]

index 2e439d0..245d0a7 100644 (file)
@@ -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
 
index f95adf1..5f9b1f2 100644 (file)
@@ -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
index 85aa9ec..6a03fde 100644 (file)
@@ -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)
index e784269..ed9d8e7 100644 (file)
@@ -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 (file)
index 0000000..814cf7a
--- /dev/null
@@ -0,0 +1,54 @@
+# 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
+
diff --git a/tests/sav/base_closure_break.sav b/tests/sav/base_closure_break.sav
new file mode 100644 (file)
index 0000000..6196664
--- /dev/null
@@ -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 (file)
index 0000000..5ac6b87
--- /dev/null
@@ -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 (file)
index 0000000..291fd47
--- /dev/null
@@ -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 (file)
index 0000000..892cd56
--- /dev/null
@@ -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 (file)
index 0000000..a05024b
--- /dev/null
@@ -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 (file)
index 0000000..4bfc47b
--- /dev/null
@@ -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 (file)
index 0000000..fc39a6c
--- /dev/null
@@ -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 (file)
index 0000000..5d74e3d
--- /dev/null
@@ -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 (file)
index 0000000..fb8d875
--- /dev/null
@@ -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 (file)
index 0000000..68c0573
--- /dev/null
@@ -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 (file)
index 0000000..80d327a
--- /dev/null
@@ -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 (file)
index 0000000..4cf1e7c
--- /dev/null
@@ -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 (file)
index 0000000..f9c3b7b
--- /dev/null
@@ -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 (file)
index 0000000..6b7c8ef
--- /dev/null
@@ -0,0 +1 @@
+alt/base_closure_break_alt9.nit:43,3--12: Error: Return with value in a procedure.