|  | // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  | // Dart test program testing closures. | 
|  |  | 
|  | import "package:expect/expect.dart"; | 
|  |  | 
|  | class LocalFunctionTest { | 
|  | LocalFunctionTest() | 
|  | : field1 = 100, | 
|  | field2_ = 200 {} | 
|  | static int f(int n) { | 
|  | int a = 0; | 
|  | g(int m) { | 
|  | a = 3 * n + m + 1; // Capture parameter n and local a. | 
|  | return a; | 
|  | } | 
|  |  | 
|  | var b = g(n); | 
|  | return a + b; | 
|  | } | 
|  |  | 
|  | static int h(int n) { | 
|  | k(int n) { | 
|  | var a = new List<dynamic>.filled(n, null); | 
|  | var b = new List<dynamic>.filled(n, null); | 
|  | int i; | 
|  | for (i = 0; i < n; i++) { | 
|  | var j = i; | 
|  | a[i] = () => i; // Captured i is always n. | 
|  | b[i] = () => j; // Captured j varies from 0 to n-1. | 
|  | } | 
|  | var a_sum = 0; | 
|  | var b_sum = 0; | 
|  | for (int i = 0; i < n; i++) { | 
|  | a_sum += a[i]() as int; | 
|  | b_sum += b[i]() as int; | 
|  | } | 
|  | return a_sum + b_sum; | 
|  | } | 
|  |  | 
|  | return k(n); | 
|  | } | 
|  |  | 
|  | static int h2(int n) { | 
|  | k(int n) { | 
|  | var a = new List<dynamic>.filled(n, null); | 
|  | var b = new List<dynamic>.filled(n, null); | 
|  | for (int i = 0; i < n; i++) { | 
|  | var j = i; | 
|  | a[i] = () => i; // Captured i varies from 0 to n-1. | 
|  | b[i] = () => j; // Captured j varies from 0 to n-1. | 
|  | } | 
|  | var a_sum = 0; | 
|  | var b_sum = 0; | 
|  | for (int i = 0; i < n; i++) { | 
|  | a_sum += a[i]() as int; | 
|  | b_sum += b[i]() as int; | 
|  | } | 
|  | return a_sum + b_sum; | 
|  | } | 
|  |  | 
|  | return k(n); | 
|  | } | 
|  |  | 
|  | int field1; | 
|  | int field2_; | 
|  | int get field2 { | 
|  | return field2_; | 
|  | } | 
|  |  | 
|  | void set field2(int value) { | 
|  | field2_ = value; | 
|  | } | 
|  |  | 
|  | int method(int n) { | 
|  | incField1() { | 
|  | field1++; | 
|  | } | 
|  |  | 
|  | incField2() { | 
|  | field2++; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < n; i++) { | 
|  | incField1(); | 
|  | incField2(); | 
|  | } | 
|  | return field1 + field2; | 
|  | } | 
|  |  | 
|  | int execute(int times, apply(int x)) { | 
|  | for (int i = 0; i < times; i++) { | 
|  | apply(i); | 
|  | } | 
|  | return field1; | 
|  | } | 
|  |  | 
|  | int testExecute(int n) { | 
|  | execute(n, (int x) { | 
|  | field1 += x; | 
|  | }); | 
|  | return field1; | 
|  | } | 
|  |  | 
|  | static int foo(int n) { | 
|  | return -100; // Wrong foo. | 
|  | } | 
|  |  | 
|  | static testSelfReference1(int n) { | 
|  | int foo(int n) { | 
|  | if (n == 0) { | 
|  | return 0; | 
|  | } else { | 
|  | return 1 + foo(n - 1); // Local foo, not static foo. | 
|  | } | 
|  | } | 
|  |  | 
|  | ; | 
|  | return foo(n); // Local foo, not static foo. | 
|  | } | 
|  |  | 
|  | static void hep(Function f) { | 
|  | f(); | 
|  | } | 
|  |  | 
|  | static testNesting(int n) { | 
|  | var a = new List<dynamic>.filled(n * n, null); | 
|  | f0() { | 
|  | for (int i = 0; i < n; i++) { | 
|  | int vi = i; | 
|  | f1() { | 
|  | for (int j = 0; j < n; j++) { | 
|  | int vj = j; | 
|  | a[i * n + j] = () => vi * n + vj; | 
|  | } | 
|  | } | 
|  |  | 
|  | f1(); | 
|  | } | 
|  | } | 
|  |  | 
|  | f0(); | 
|  | int result = 0; | 
|  | for (int k = 0; k < n * n; k++) { | 
|  | Expect.equals(k, a[k]()); | 
|  | result += a[k]() as int; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static var field5; | 
|  | static var set_field5_func; | 
|  | static testClosureCallStatement(int x) { | 
|  | LocalFunctionTest.set_field5_func = (int n) { | 
|  | field5 = n * n; | 
|  | }; | 
|  | (LocalFunctionTest.set_field5_func)(x); | 
|  | Expect.equals(x * x, LocalFunctionTest.field5); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static testExceptions() { | 
|  | dynamic f = (int n) => n + 1; | 
|  | Expect.equals(2, f(1)); | 
|  | Expect.equals(true, f is Function); | 
|  | Expect.equals(true, f is Object); | 
|  | Expect.equals(true, f.toString().startsWith("Closure")); | 
|  | bool exception_caught = false; | 
|  | try { | 
|  | f(1, 2); | 
|  | } on NoSuchMethodError catch (e) { | 
|  | exception_caught = true; | 
|  | } | 
|  | Expect.equals(true, exception_caught); | 
|  | exception_caught = false; | 
|  | try { | 
|  | f(); | 
|  | } on NoSuchMethodError catch (e) { | 
|  | exception_caught = true; | 
|  | } | 
|  | Expect.equals(true, exception_caught); | 
|  | exception_caught = false; | 
|  | try { | 
|  | f.xyz(0); | 
|  | } on NoSuchMethodError catch (e) { | 
|  | exception_caught = true; | 
|  | } | 
|  | Expect.equals(true, exception_caught); | 
|  |  | 
|  | // Overwrite closure value. | 
|  | f = 3; | 
|  | exception_caught = false; | 
|  | try { | 
|  | f(1); | 
|  | } on NoSuchMethodError catch (e) { | 
|  | exception_caught = true; | 
|  | } | 
|  | Expect.equals(true, exception_caught); | 
|  |  | 
|  | // Do not expect any exceptions to be thrown. | 
|  | var g = ([int n = 1]) => n + 1; | 
|  | Expect.equals(2, g()); | 
|  | Expect.equals(3, g(2)); | 
|  | } | 
|  |  | 
|  | static int doThis(int n, int f(int n)) { | 
|  | return f(n); | 
|  | } | 
|  |  | 
|  | static testMain() { | 
|  | Expect.equals(2 * (3 * 2 + 2 + 1), f(2)); | 
|  | Expect.equals(10 * 10 + 10 * 9 / 2, h(10)); | 
|  | Expect.equals(90, h2(10)); | 
|  | Expect.equals(320, new LocalFunctionTest().method(10)); | 
|  | Expect.equals(145, new LocalFunctionTest().testExecute(10)); | 
|  | Expect.equals(5, testSelfReference1(5)); | 
|  | Expect.equals(24 * 25 / 2, testNesting(5)); | 
|  | Expect.equals(true, testClosureCallStatement(7)); | 
|  | Expect.equals(99, doThis(10, (n) => n * n - 1)); | 
|  | testExceptions(); | 
|  | } | 
|  | } | 
|  |  | 
|  | main() { | 
|  | LocalFunctionTest.testMain(); | 
|  | } |