syntax: closure are designed by their names, not their ranks
authorJean Privat <jean@pryen.org>
Sat, 1 Aug 2009 02:44:33 +0000 (22:44 -0400)
committerJean Privat <jean@pryen.org>
Sat, 1 Aug 2009 02:44:33 +0000 (22:44 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

12 files changed:
src/metamodel/static_type.nit
src/syntax/icode_generation.nit
src/syntax/mmbuilder.nit
src/syntax/typing.nit
tests/base_closure_multi.nit
tests/sav/base_closure1_alt12.sav [new file with mode: 0644]
tests/sav/base_closure8_alt4.fail [deleted file]
tests/sav/base_closure8_alt4.sav [new file with mode: 0644]
tests/sav/base_closure_continue_assign_alt3.fail [deleted file]
tests/sav/base_closure_continue_assign_alt3.sav [moved from tests/sav/base_closure1_alt12.fail with 57% similarity]
tests/sav/base_closure_multi_alt6.sav [new file with mode: 0644]
tests/test_closure_inlined_return.nit

index 541e3e5..3c34a9b 100644 (file)
@@ -81,6 +81,15 @@ class MMSignature
        # The closure parameters
        readable var _closures: Array[MMClosure] = new Array[MMClosure]
 
+       # Return the closure named 'name'. Null if no such a closure exists.
+       fun closure_named(name: Symbol): nullable MMClosure
+       do
+               for c in _closures do
+                       if c.name == name then return c
+               end
+               return null
+       end
+
        # Number of parameters
        fun arity: Int
        do
@@ -214,6 +223,9 @@ end
 
 # A closure in a signature
 class MMClosure
+       # The name of the closure (without the !)
+       readable var _name: Symbol
+
        # The signature of the closure
        readable var _signature: MMSignature
 
@@ -228,11 +240,12 @@ class MMClosure
        # Adapt the signature to a different receiver
        fun adaptation_to(r: MMType): MMClosure
        do
-               return new MMClosure(_signature.adaptation_to(r), _is_break, _is_optional)
+               return new MMClosure(_name, _signature.adaptation_to(r), _is_break, _is_optional)
        end
 
-       init(s: MMSignature, is_break: Bool, is_optional: Bool)
+       init(name: Symbol, s: MMSignature, is_break: Bool, is_optional: Bool)
        do
+               _name = name
                _signature = s
                _is_break = is_break
                _is_optional = is_optional
@@ -242,7 +255,7 @@ class MMClosure
        do
                var sig = _signature.not_for_self
                if sig != _signature then
-                       return new MMClosure(sig, _is_break, _is_optional)
+                       return new MMClosure(_name, sig, _is_break, _is_optional)
                else
                        return self
                end
index f002863..b87f91c 100644 (file)
@@ -1244,14 +1244,24 @@ redef class ASendExpr
                        closcns = new Array[nullable IClosureDef]
                        var cdarity = 0
                        if closure_defs != null then cdarity = closure_defs.length
-                       for i in [0..cdarity[ do
-                               closure_defs[i].escapable.break_seq = seq
-                               closure_defs[i].escapable.break_value = r
-                               var cn = closure_defs[i].generate_iclosuredef(v)
-                               closcns.add(cn)
-                       end
-                       for i in [cdarity..prop_signature.closures.length[ do
-                               closcns.add(null)
+                       var closure_defs = closure_defs
+                       for mmc in prop_signature.closures do
+                               var found = false
+                               var name = mmc.name
+                               if closure_defs != null then
+                                       for cd in closure_defs do
+                                               if cd.n_id.to_symbol != name then continue
+                                               assert found == false
+                                               found = true
+                                               cd.escapable.break_seq = seq
+                                               cd.escapable.break_value = r
+                                               var cn = cd.generate_iclosuredef(v)
+                                               closcns.add(cn)
+                                       end
+                               end
+                               if not found then
+                                       closcns.add(null)
+                               end
                        end
                end
 
index 60deaf2..52855c8 100644 (file)
@@ -1228,10 +1228,17 @@ redef class AClosureDecl
 
                # Add the finalizer to the closure signature
                var finalize_sig = new MMSignature(new Array[MMType], null, v.module.type_any) # FIXME should be no receiver
-               var finalizer_clos = new MMClosure(finalize_sig, false, true)
+               var finalizer_clos = new MMClosure(once ("break".to_symbol), finalize_sig, false, true)
                sig.closures.add(finalizer_clos)
 
-               var clos = new MMClosure(sig, n_kwbreak != null, n_expr != null)
+               var name = n_id.to_symbol
+               var clos = new MMClosure(name, sig, n_kwbreak != null, n_expr != null)
+               for c in old_signature_builder.closure_decls do
+                       if c.n_id.to_symbol == name then
+                               v.error(n_id, "A closure '!{name}' already defined at {c.n_id.location.relative_to(n_id.location)}.")
+                               return
+                       end
+               end
                v.signature_builder = old_signature_builder
                _position = old_signature_builder.closure_decls.length
                old_signature_builder.closure_decls.add(self)
index 0f19f7f..78a9498 100644 (file)
@@ -1124,12 +1124,23 @@ redef class AAbsAbsSendExpr
 
                                # Process each closure definition
                                for i in [0..arity[ do
-                                       var csi = cs[i]
                                        var cdi = cd[i]
-                                       var esc = new EscapableClosure(cdi, csi, break_list)
-                                       v.escapable_ctx.push(esc, n_label)
-                                       cdi.accept_typing2(v, esc)
-                                       v.escapable_ctx.pop
+                                       var cni = cdi.n_id.to_symbol
+                                       var csi = psig.closure_named(cni)
+                                       if csi != null then
+                                               var esc = new EscapableClosure(cdi, csi, break_list)
+                                               v.escapable_ctx.push(esc, n_label)
+                                               cdi.accept_typing2(v, esc)
+                                               v.escapable_ctx.pop
+                                       else if cs.length == 1 then
+                                               v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closure is !{cs.first.name}.")
+                                       else
+                                               var a = new Array[String]
+                                               for c in cs do
+                                                       a.add("!{c.name}")
+                                               end
+                                               v.error(cdi.n_id, "Error: no closure named '!{cni}' in {name}; only closures are {a.join(",")}.")
+                                       end
                                end
 
                                # Check break type conformity
@@ -1567,6 +1578,16 @@ redef class AClosureCallExpr
        end
 end
 
+redef class AClosureId
+       fun to_symbol: Symbol is abstract
+end
+redef class ASimpleClosureId
+       redef fun to_symbol: Symbol do return n_id.to_symbol
+end
+redef class ABreakClosureId
+       redef fun to_symbol: Symbol do return n_kwbreak.to_symbol
+end
+
 redef class AClosureDef
        var _closure: nullable MMClosure
        redef fun closure do return _closure.as(not null)
index f533838..65df401 100644 (file)
 # limitations under the License.
 
 import kernel
-
 fun a
        !a1
        !a2 #!alt1#
 #alt2# !a3
+#alt6#  !a1
 do
        a1
        a2 #!alt1#
diff --git a/tests/sav/base_closure1_alt12.sav b/tests/sav/base_closure1_alt12.sav
new file mode 100644 (file)
index 0000000..672b85a
--- /dev/null
@@ -0,0 +1 @@
+alt/base_closure1_alt12.nit:46,10--12: Error: no closure named '!baz' in foo; only closure is !bar.
diff --git a/tests/sav/base_closure8_alt4.fail b/tests/sav/base_closure8_alt4.fail
deleted file mode 100644 (file)
index 6948f2d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-0
-[1
-2
-[3
-4
-5
-4
-5
-]3
-6
-2
-[3
-4
-5
-4
-5
-]3
-6
-]1
-7
-8
diff --git a/tests/sav/base_closure8_alt4.sav b/tests/sav/base_closure8_alt4.sav
new file mode 100644 (file)
index 0000000..338aa5f
--- /dev/null
@@ -0,0 +1 @@
+alt/base_closure8_alt4.nit:29,8--10: Error: no closure named '!baz' in bar; only closure is !break.
diff --git a/tests/sav/base_closure_continue_assign_alt3.fail b/tests/sav/base_closure_continue_assign_alt3.fail
deleted file mode 100644 (file)
index 3a76f19..0000000
+++ /dev/null
@@ -1 +0,0 @@
-alt/base_closure_continue_assign_alt3.nit:47,10: Error: continue without value required in this block.
diff --git a/tests/sav/base_closure_multi_alt6.sav b/tests/sav/base_closure_multi_alt6.sav
new file mode 100644 (file)
index 0000000..1c9b3cb
--- /dev/null
@@ -0,0 +1 @@
+alt/base_closure_multi_alt6.nit:22,4--5: A closure '!a1' already defined at 19,3--4.
index 3a7f3d6..cf5f034 100644 (file)
@@ -16,7 +16,7 @@ do
        0.output
        var i = 0
        while i < 3 do
-               foo !each do
+               foo !k do
                        ' '.output
                        ' '.output
                        '<'.output