diff --git a/pkg/args/lib/args.dart b/pkg/args/lib/args.dart index 12ea74549cc..0cb81961a3e 100644 --- a/pkg/args/lib/args.dart +++ b/pkg/args/lib/args.dart @@ -353,7 +353,7 @@ class ArgParser { _setOption(Map results, _Option option, value) { // See if it's one of the allowed values. if (option.allowed != null) { - _validate(option.allowed.some((allow) => allow == value), + _validate(option.allowed.any((allow) => allow == value), '"$value" is not an allowed value for option "${option.name}".'); } @@ -544,7 +544,7 @@ class ArgResults { } /** Get the names of the options as a [Collection]. */ - Collection get options => _options.keys; + Collection get options => _options.keys.toList(); } class _Option { @@ -630,8 +630,8 @@ class _Usage { if (option.help != null) write(2, option.help); if (option.allowedHelp != null) { - var allowedNames = option.allowedHelp.keys; - allowedNames.sort((a, b) => a.compareTo(b)); + var allowedNames = option.allowedHelp.keys.toList(); + allowedNames.sort(); newline(); for (var name in allowedNames) { write(1, getAllowedTitle(name)); diff --git a/pkg/args/test/args_test.dart b/pkg/args/test/args_test.dart index 11627f3f8be..6feb1dcec26 100644 --- a/pkg/args/test/args_test.dart +++ b/pkg/args/test/args_test.dart @@ -450,8 +450,8 @@ main() { parser.addOption('meow', defaultsTo: 'kitty'); var args = parser.parse([]); expect(args.options, hasLength(2)); - expect(args.options.some((o) => o == 'woof'), isTrue); - expect(args.options.some((o) => o == 'meow'), isTrue); + expect(args.options.any((o) => o == 'woof'), isTrue); + expect(args.options.any((o) => o == 'meow'), isTrue); }); }); diff --git a/pkg/fixnum/lib/src/int32.dart b/pkg/fixnum/lib/src/int32.dart index ac92a7e1b4b..bbff8a0abdf 100644 --- a/pkg/fixnum/lib/src/int32.dart +++ b/pkg/fixnum/lib/src/int32.dart @@ -338,7 +338,7 @@ class int32 implements intx { int numberOfTrailingZeros() => _numberOfTrailingZeros(_i); List toBytes() { - List result = new List(4); + List result = new List.fixedLength(4); result[0] = _i & 0xff; result[1] = (_i >> 8) & 0xff; result[2] = (_i >> 16) & 0xff; diff --git a/pkg/fixnum/lib/src/int64.dart b/pkg/fixnum/lib/src/int64.dart index 3ef0bc09be1..b2a263f273e 100644 --- a/pkg/fixnum/lib/src/int64.dart +++ b/pkg/fixnum/lib/src/int64.dart @@ -625,7 +625,7 @@ class int64 implements intx { } List toBytes() { - List result = new List(8); + List result = new List.fixedLength(8); result[0] = _l & 0xff; result[1] = (_l >> 8) & 0xff; result[2] = ((_m << 6) & 0xfc) | ((_l >> 16) & 0x3f); diff --git a/pkg/fixnum/test/int_64_vm_test.dart b/pkg/fixnum/test/int_64_vm_test.dart index ee1fd74299b..03ce1120a06 100644 --- a/pkg/fixnum/test/int_64_vm_test.dart +++ b/pkg/fixnum/test/int_64_vm_test.dart @@ -174,7 +174,7 @@ class int64VMTest { testSet.add(new int64.fromInt(pow)); } - TEST_VALUES = new List(testSet.length); + TEST_VALUES = new List.fixedLength(testSet.length); int index = 0; for (int64 val in testSet) { TEST_VALUES[index++] = val; diff --git a/pkg/http/lib/http.dart b/pkg/http/lib/http.dart index ee074f77a42..bb59726cf73 100644 --- a/pkg/http/lib/http.dart +++ b/pkg/http/lib/http.dart @@ -27,7 +27,7 @@ /// "http://example.com/whatsit/create", /// fields: {"name": "doodle", "color": "blue"}) /// .chain((response) => client.get(response.bodyFields['uri'])) -/// .transform((response) => print(response.body)) +/// .then((response) => print(response.body)) /// .onComplete((_) => client.close()); /// /// You can also exert more fine-grained control over your requests and @@ -53,6 +53,7 @@ library http; +import 'dart:async'; import 'dart:scalarlist'; import 'dart:uri'; @@ -168,6 +169,6 @@ Future readBytes(url, {Map headers}) => Future _withClient(Future fn(Client)) { var client = new Client(); var future = fn(client); - future.onComplete((_) => client.close()); + future.catchError((_) {}).then((_) => client.close()); return future; } diff --git a/pkg/http/lib/src/base_client.dart b/pkg/http/lib/src/base_client.dart index 1662f003719..d3a3736897f 100644 --- a/pkg/http/lib/src/base_client.dart +++ b/pkg/http/lib/src/base_client.dart @@ -4,6 +4,7 @@ library base_client; +import 'dart:async'; import 'dart:io'; import 'dart:scalarlist'; import 'dart:uri'; @@ -72,7 +73,7 @@ abstract class BaseClient implements Client { /// For more fine-grained control over the request and response, use [send] or /// [get] instead. Future read(url, {Map headers}) { - return get(url, headers: headers).transform((response) { + return get(url, headers: headers).then((response) { _checkResponseSuccess(url, response); return response.body; }); @@ -88,7 +89,7 @@ abstract class BaseClient implements Client { /// For more fine-grained control over the request and response, use [send] or /// [get] instead. Future readBytes(url, {Map headers}) { - return get(url, headers: headers).transform((response) { + return get(url, headers: headers).then((response) { _checkResponseSuccess(url, response); return response.bodyBytes; }); @@ -108,7 +109,7 @@ abstract class BaseClient implements Client { [Map fields]) { // Wrap everything in a Future block so that synchronous validation errors // are passed asynchronously through the Future chain. - return async.chain((_) { + return async.then((_) { if (url is String) url = new Uri.fromString(url); var request = new Request(method, url); @@ -116,7 +117,7 @@ abstract class BaseClient implements Client { if (fields != null && !fields.isEmpty) request.bodyFields = fields; return send(request); - }).chain(Response.fromStream); + }).then(Response.fromStream); } /// Throws an error if [response] is not successful. diff --git a/pkg/http/lib/src/base_request.dart b/pkg/http/lib/src/base_request.dart index eb36703eaf6..41f04917d93 100644 --- a/pkg/http/lib/src/base_request.dart +++ b/pkg/http/lib/src/base_request.dart @@ -4,6 +4,7 @@ library base_request; +import 'dart:async'; import 'dart:io'; import 'dart:isolate'; import 'dart:uri'; @@ -105,7 +106,7 @@ abstract class BaseRequest { /// requests. Future send() { var client = new Client(); - return client.send(this).transform((response) { + return client.send(this).then((response) { // TODO(nweiz): This makes me sick to my stomach, but it's currently the // best way to listen for the response stream being closed. Kill it with // fire once issue 4202 is fixed. @@ -117,7 +118,7 @@ abstract class BaseRequest { }); return response; - }); + }).catchError((_) { client.close(); }); } /// Throws an error if this request has been finalized. diff --git a/pkg/http/lib/src/client.dart b/pkg/http/lib/src/client.dart index 229429f52b7..204109ee5a1 100644 --- a/pkg/http/lib/src/client.dart +++ b/pkg/http/lib/src/client.dart @@ -4,6 +4,7 @@ library client; +import 'dart:async'; import 'dart:io'; import 'dart:scalarlist'; diff --git a/pkg/http/lib/src/io_client.dart b/pkg/http/lib/src/io_client.dart index e3f141352a7..d5b40cba517 100644 --- a/pkg/http/lib/src/io_client.dart +++ b/pkg/http/lib/src/io_client.dart @@ -4,6 +4,7 @@ library io_client; +import 'dart:async'; import 'dart:io'; import 'base_client.dart'; @@ -25,6 +26,7 @@ class IOClient extends BaseClient { var completer = new Completer(); var connection = _inner.openUrl(request.method, request.url); + bool completed = false; connection.followRedirects = request.followRedirects; connection.maxRedirects = request.maxRedirects; connection.onError = (e) { @@ -33,9 +35,10 @@ class IOClient extends BaseClient { // onRequest or onResponse callbacks get passed to onError. If the // completer has already fired, we want to re-throw those exceptions // to the top level so that they aren't silently ignored. - if (completer.future.isComplete) throw e; + if (completed) throw e; - completer.completeException(e); + completed = true; + completer.completeError(e); }); }; @@ -57,6 +60,9 @@ class IOClient extends BaseClient { var headers = {}; response.headers.forEach((key, value) => headers[key] = value); + if (completed) return; + + completed = true; completer.complete(new StreamedResponse( response.inputStream, response.statusCode, diff --git a/pkg/http/lib/src/mock_client.dart b/pkg/http/lib/src/mock_client.dart index 90c5d192603..8af54743948 100644 --- a/pkg/http/lib/src/mock_client.dart +++ b/pkg/http/lib/src/mock_client.dart @@ -4,6 +4,7 @@ library mock_client; +import 'dart:async'; import 'dart:io'; import 'base_client.dart'; @@ -31,7 +32,7 @@ class MockClient extends BaseClient { /// [Response]s. MockClient(MockClientHandler fn) : this._((baseRequest, bodyStream) { - return consumeInputStream(bodyStream).chain((bodyBytes) { + return consumeInputStream(bodyStream).then((bodyBytes) { var request = new Request(baseRequest.method, baseRequest.url); request.persistentConnection = baseRequest.persistentConnection; request.followRedirects = baseRequest.followRedirects; @@ -41,7 +42,7 @@ class MockClient extends BaseClient { request.finalize(); return fn(request); - }).transform((response) { + }).then((response) { var stream = new ListInputStream(); stream.write(response.bodyBytes); stream.markEndOfStream(); @@ -62,7 +63,7 @@ class MockClient extends BaseClient { /// sends [StreamedResponse]s. MockClient.streaming(MockClientStreamHandler fn) : this._((request, bodyStream) { - return fn(request, bodyStream).transform((response) { + return fn(request, bodyStream).then((response) { return new StreamedResponse( response.stream, response.statusCode, @@ -78,7 +79,7 @@ class MockClient extends BaseClient { /// Sends a request. Future send(BaseRequest request) { var bodyStream = request.finalize(); - return async.chain((_) => _handler(request, bodyStream)); + return async.then((_) => _handler(request, bodyStream)); } } diff --git a/pkg/http/lib/src/multipart_file.dart b/pkg/http/lib/src/multipart_file.dart index 9894b3dad88..5677a399f7f 100644 --- a/pkg/http/lib/src/multipart_file.dart +++ b/pkg/http/lib/src/multipart_file.dart @@ -85,7 +85,7 @@ class MultipartFile { static Future fromFile(String field, File file, {String filename, ContentType contentType}) { if (filename == null) filename = new Path(file.name).filename; - return file.length().transform((length) { + return file.length().then((length) { return new MultipartFile(field, file.openInputStream(), length, filename: filename, contentType: contentType); diff --git a/pkg/http/lib/src/multipart_request.dart b/pkg/http/lib/src/multipart_request.dart index 3cd0dc405b3..4d744c12210 100644 --- a/pkg/http/lib/src/multipart_request.dart +++ b/pkg/http/lib/src/multipart_request.dart @@ -4,6 +4,7 @@ library multipart_request; +import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'dart:uri'; @@ -106,7 +107,7 @@ class MultipartRequest extends BaseRequest { writeAscii('--$boundary\r\n'); writeAscii(_headerForFile(file)); return writeInputToInput(file.finalize(), stream) - .transform((_) => writeLine()); + .then((_) => writeLine()); }).then((_) { // TODO(nweiz): pass any errors propagated through this future on to // the stream. See issue 3657. @@ -156,7 +157,7 @@ class MultipartRequest extends BaseRequest { /// [length]. String _boundaryString(int length) { var prefix = "dart-http-boundary-"; - var list = new List(length - prefix.length); + var list = new List.fixedLength(length - prefix.length); for (var i = 0; i < list.length; i++) { list[i] = _BOUNDARY_CHARACTERS[ _random.nextInt(_BOUNDARY_CHARACTERS.length)]; diff --git a/pkg/http/lib/src/response.dart b/pkg/http/lib/src/response.dart index 26e5e61f68e..859b57a8b43 100644 --- a/pkg/http/lib/src/response.dart +++ b/pkg/http/lib/src/response.dart @@ -4,6 +4,7 @@ library response; +import 'dart:async'; import 'dart:io'; import 'dart:scalarlist'; @@ -65,7 +66,7 @@ class Response extends BaseResponse { /// Creates a new HTTP response by waiting for the full body to become /// available from a [StreamedResponse]. static Future fromStream(StreamedResponse response) { - return consumeInputStream(response.stream).transform((body) { + return consumeInputStream(response.stream).then((body) { return new Response.bytes( body, response.statusCode, diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart index 1a9aff347e1..0a82dfd1225 100644 --- a/pkg/http/lib/src/utils.dart +++ b/pkg/http/lib/src/utils.dart @@ -4,9 +4,9 @@ library utils; +import 'dart:async'; import 'dart:crypto'; import 'dart:io'; -import 'dart:isolate'; import 'dart:scalarlist'; import 'dart:uri'; import 'dart:utf'; @@ -36,7 +36,7 @@ String mapToQuery(Map map) { var pairs = >[]; map.forEach((key, value) => pairs.add([encodeUriComponent(key), encodeUriComponent(value)])); - return Strings.join(pairs.map((pair) => "${pair[0]}=${pair[1]}"), "&"); + return Strings.join(pairs.mappedBy((pair) => "${pair[0]}=${pair[1]}"), "&"); } /// Adds all key/value pairs from [source] to [destination], overwriting any @@ -140,7 +140,7 @@ Future> consumeInputStream(InputStream stream) { var buffer = []; stream.onClosed = () => completer.complete(buffer); stream.onData = () => buffer.addAll(stream.read()); - stream.onError = completer.completeException; + stream.onError = completer.completeError; return completer.future; } @@ -183,10 +183,10 @@ Future get async { /// The return values of all [Future]s are discarded. Any errors will cause the /// iteration to stop and will be piped through the return value. Future forEachFuture(Iterable input, Future fn(element)) { - var iterator = input.iterator(); + var iterator = input.iterator; Future nextElement(_) { - if (!iterator.hasNext) return new Future.immediate(null); - return fn(iterator.next()).chain(nextElement); + if (!iterator.moveNext()) return new Future.immediate(null); + return fn(iterator.current).then(nextElement); } return nextElement(null); } diff --git a/pkg/http/lib/testing.dart b/pkg/http/lib/testing.dart index 2d9ccaf22f7..4c750ce34a9 100644 --- a/pkg/http/lib/testing.dart +++ b/pkg/http/lib/testing.dart @@ -10,14 +10,14 @@ library testing; /// allows test code to set up a local request handler in order to fake a server /// that responds to HTTP requests: /// -/// import 'dart:json'; +/// import 'dart:json' as json; /// import 'package:http/testing.dart'; /// /// var client = new MockClient((request) { /// if (request.url.path != "/data.json") { /// return new Response("", 404); /// } -/// return new Response(JSON.stringify({ +/// return new Response(json.stringify({ /// 'numbers': [1, 4, 15, 19, 214] /// }, 200, headers: { /// 'content-type': 'application/json' diff --git a/pkg/http/test/client_test.dart b/pkg/http/test/client_test.dart index 009f1472ca1..e837ba8c9b7 100644 --- a/pkg/http/test/client_test.dart +++ b/pkg/http/test/client_test.dart @@ -21,12 +21,12 @@ void main() { request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json; charset=utf-8'; - var future = client.send(request).chain((response) { + var future = client.send(request).then((response) { expect(response.request, equals(request)); expect(response.statusCode, equals(200)); return consumeInputStream(response.stream); - }).transform((bytes) => new String.fromCharCodes(bytes)); - future.onComplete((_) => client.close()); + }).then((bytes) => new String.fromCharCodes(bytes)); + future.catchError((_) {}).then((_) => client.close()); expect(future, completion(parse(equals({ 'method': 'POST', diff --git a/pkg/http/test/http_test.dart b/pkg/http/test/http_test.dart index d9ffa7d4ac0..64e06d31a85 100644 --- a/pkg/http/test/http_test.dart +++ b/pkg/http/test/http_test.dart @@ -16,17 +16,17 @@ main() { tearDown(stopServer); test('head', () { - expect(http.head(serverUrl).transform((response) { + expect(http.head(serverUrl).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, equals('')); - }), completes); + })), completes); }); test('get', () { expect(http.get(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((response) { + }).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'GET', @@ -37,7 +37,7 @@ main() { 'x-other-header': ['Other Value'] }, }))); - }), completes); + })), completes); }); test('post', () { @@ -47,7 +47,7 @@ main() { }, fields: { 'some-field': 'value', 'other-field': 'other value' - }).transform((response) { + }).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'POST', @@ -62,7 +62,7 @@ main() { }, 'body': 'some-field=value&other-field=other+value' }))); - }), completes); + })), completes); }); test('post without fields', () { @@ -70,7 +70,7 @@ main() { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value', 'Content-Type': 'text/plain' - }).transform((response) { + }).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'POST', @@ -82,7 +82,7 @@ main() { 'x-other-header': ['Other Value'] } }))); - }), completes); + })), completes); }); test('put', () { @@ -92,7 +92,7 @@ main() { }, fields: { 'some-field': 'value', 'other-field': 'other value' - }).transform((response) { + }).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'PUT', @@ -107,7 +107,7 @@ main() { }, 'body': 'some-field=value&other-field=other+value' }))); - }), completes); + })), completes); }); test('put without fields', () { @@ -115,7 +115,7 @@ main() { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value', 'Content-Type': 'text/plain' - }).transform((response) { + }).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'PUT', @@ -127,14 +127,14 @@ main() { 'x-other-header': ['Other Value'] } }))); - }), completes); + })), completes); }); test('delete', () { expect(http.delete(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((response) { + }).then(expectAsync1((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'DELETE', @@ -145,14 +145,14 @@ main() { 'x-other-header': ['Other Value'] } }))); - }), completes); + })), completes); }); test('read', () { expect(http.read(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }), completion(parse(equals({ + }).then(expectAsync1((val) => val)), completion(parse(equals({ 'method': 'GET', 'path': '/', 'headers': { @@ -162,16 +162,17 @@ main() { }, })))); }); - + test('read throws an error for a 4** status code', () { - expect(http.read(serverUrl.resolve('/error')), throwsHttpException); + expect(http.read(serverUrl.resolve('/error')).then((expectAsync1(x) => x)), + throwsHttpException); }); - + test('readBytes', () { var future = http.readBytes(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((bytes) => new String.fromCharCodes(bytes)); + }).then(expectAsync1((bytes) => new String.fromCharCodes(bytes))); expect(future, completion(parse(equals({ 'method': 'GET', @@ -185,7 +186,8 @@ main() { }); test('readBytes throws an error for a 4** status code', () { - expect(http.readBytes(serverUrl.resolve('/error')), throwsHttpException); + expect(http.readBytes(serverUrl.resolve('/error')).then((expectAsync1(x) => x)), + throwsHttpException); }); }); } diff --git a/pkg/http/test/mock_client_test.dart b/pkg/http/test/mock_client_test.dart index 2dab7befc26..01581a8197c 100644 --- a/pkg/http/test/mock_client_test.dart +++ b/pkg/http/test/mock_client_test.dart @@ -4,8 +4,9 @@ library mock_client_test; +import 'dart:async'; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:uri'; import 'package:unittest/unittest.dart'; @@ -18,14 +19,14 @@ void main() { test('handles a request', () { var client = new MockClient((request) { return new Future.immediate(new http.Response( - JSON.stringify(request.bodyFields), 200, + json.stringify(request.bodyFields), 200, request: request, headers: {'content-type': 'application/json'})); }); expect(client.post("http://example.com/foo", fields: { 'field1': 'value1', 'field2': 'value2' - }).transform((response) => response.body), completion(parse(equals({ + }).then((response) => response.body), completion(parse(equals({ 'field1': 'value1', 'field2': 'value2' })))); @@ -33,7 +34,7 @@ void main() { test('handles a streamed request', () { var client = new MockClient.streaming((request, bodyStream) { - return consumeInputStream(bodyStream).transform((body) { + return consumeInputStream(bodyStream).then((body) { var stream = new ListInputStream(); async.then((_) { var bodyString = new String.fromCharCodes(body); @@ -49,8 +50,8 @@ void main() { var request = new http.Request("POST", uri); request.body = "hello, world"; var future = client.send(request) - .chain(http.Response.fromStream) - .transform((response) => response.body); + .then(http.Response.fromStream) + .then((response) => response.body); expect(future, completion(equals('Request body was "hello, world"'))); }); diff --git a/pkg/http/test/multipart_test.dart b/pkg/http/test/multipart_test.dart index abbd5094d3a..0e66bf3cbcd 100644 --- a/pkg/http/test/multipart_test.dart +++ b/pkg/http/test/multipart_test.dart @@ -29,7 +29,7 @@ class _BodyMatches extends BaseMatcher { bool matches(item, MatchState matchState) { if (item is! http.MultipartRequest) return false; - var future = consumeInputStream(item.finalize()).transform((bodyBytes) { + var future = consumeInputStream(item.finalize()).then((bodyBytes) { var body = decodeUtf8(bodyBytes); var contentType = new ContentType.fromString( item.headers['content-type']); diff --git a/pkg/http/test/request_test.dart b/pkg/http/test/request_test.dart index bb4cdb01724..1d805aa4ffb 100644 --- a/pkg/http/test/request_test.dart +++ b/pkg/http/test/request_test.dart @@ -17,11 +17,11 @@ void main() { var request = new http.Request('POST', serverUrl); request.body = "hello"; - var future = request.send().chain((response) { + var future = request.send().then((response) { expect(response.statusCode, equals(200)); return consumeInputStream(response.stream); - }).transform((bytes) => new String.fromCharCodes(bytes)); - future.onComplete(expectAsync1((_) { + }).then((bytes) => new String.fromCharCodes(bytes)); + future.catchError((_) {}).then(expectAsync1((_) { stopServer(); })); @@ -192,11 +192,11 @@ void main() { var request = new http.Request('POST', serverUrl.resolve('/redirect')) ..followRedirects = false; - var future = request.send().transform((response) { + var future = request.send().then((response) { print("#followRedirects test response received"); expect(response.statusCode, equals(302)); }); - future.onComplete(expectAsync1((_) { + future.catchError((_) {}).then(expectAsync1((_) { print("#followRedirects test stopping server..."); stopServer(); print("#followRedirects test server stopped"); @@ -215,12 +215,12 @@ void main() { var request = new http.Request('POST', serverUrl.resolve('/loop?1')) ..maxRedirects = 2; - var future = request.send().transformException((e) { + var future = request.send().catchError((AsyncError e) { print("#maxRedirects test exception received"); - expect(e, isRedirectLimitExceededException); - expect(e.redirects.length, equals(2)); + expect(e.error, isRedirectLimitExceededException); + expect(e.error.redirects.length, equals(2)); }); - future.onComplete(expectAsync1((_) { + future.catchError((_) {}).then(expectAsync1((_) { print("#maxRedirects test stopping server..."); stopServer(); print("#maxRedirects test server stopped"); @@ -318,7 +318,7 @@ void main() { request.body = "Hello, world!"; expect( consumeInputStream(request.finalize()) - .transform((bytes) => new String.fromCharCodes(bytes)), + .then((bytes) => new String.fromCharCodes(bytes)), completion(equals("Hello, world!"))); }); diff --git a/pkg/http/test/response_test.dart b/pkg/http/test/response_test.dart index 04d3f3ba89c..ba09738849b 100644 --- a/pkg/http/test/response_test.dart +++ b/pkg/http/test/response_test.dart @@ -46,7 +46,7 @@ void main() { var stream = new ListInputStream(); var streamResponse = new http.StreamedResponse(stream, 200, 13); var future = http.Response.fromStream(streamResponse) - .transform((response) => response.body); + .then((response) => response.body); expect(future, completion(equals("Hello, world!"))); stream.write([72, 101, 108, 108, 111, 44, 32]); @@ -58,7 +58,7 @@ void main() { var stream = new ListInputStream(); var streamResponse = new http.StreamedResponse(stream, 200, 5); var future = http.Response.fromStream(streamResponse) - .transform((response) => response.bodyBytes); + .then((response) => response.bodyBytes); expect(future, completion(equals([104, 101, 108, 108, 111]))); stream.write([104, 101, 108, 108, 111]); diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart index 89440f88341..9e9ae8b3408 100644 --- a/pkg/http/test/utils.dart +++ b/pkg/http/test/utils.dart @@ -5,7 +5,7 @@ library test_utils; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:uri'; import 'package:unittest/unittest.dart'; @@ -88,7 +88,7 @@ void startServer() { outputEncoding = Encoding.ASCII; } - var body = JSON.stringify(content); + var body = json.stringify(content); response.contentLength = body.length; response.outputStream.writeString(body, outputEncoding); response.outputStream.close(); @@ -118,7 +118,7 @@ class _Parse extends BaseMatcher { var parsed; try { - parsed = JSON.parse(item); + parsed = json.parse(item); } catch (e) { return false; } diff --git a/pkg/intl/example/basic/basic_example.dart b/pkg/intl/example/basic/basic_example.dart index 76380e90d12..68ec5944719 100644 --- a/pkg/intl/example/basic/basic_example.dart +++ b/pkg/intl/example/basic/basic_example.dart @@ -19,6 +19,7 @@ library intl_basic_example; // These can be replaced with package:intl/... references if using this in // a separate package. // TODO(alanknight): Replace these with package: once pub works in buildbots. +import 'dart:async'; import '../../lib/date_symbol_data_local.dart'; import '../../lib/intl.dart'; import '../../lib/message_lookup_local.dart'; @@ -57,8 +58,8 @@ runProgram(List _) { printForLocale(aDate, de, runAt); printForLocale(aDate, th, runAt); // Example making use of the return value from withLocale; - var useReturnValue = Intl.withLocale(th.locale, () => runAt('now', 'today')); - doThisWithTheOutput(useReturnValue); + Intl.withLocale(th.locale, () => runAt('now', 'today')) + .then(doThisWithTheOutput); } printForLocale(aDate, intl, operation) { @@ -66,5 +67,7 @@ printForLocale(aDate, intl, operation) { var dayFormat = intl.date().add_yMMMMEEEEd(); var time = hmsFormat.format(aDate); var day = dayFormat.format(aDate); - Intl.withLocale(intl.locale, () { doThisWithTheOutput(operation(time,day));}); -} \ No newline at end of file + Intl.withLocale(intl.locale, () { + operation(time,day).then(doThisWithTheOutput); + }); +} diff --git a/pkg/intl/lib/bidi_utils.dart b/pkg/intl/lib/bidi_utils.dart index f6cb86cdfe7..b6bb0070df5 100644 --- a/pkg/intl/lib/bidi_utils.dart +++ b/pkg/intl/lib/bidi_utils.dart @@ -186,7 +186,7 @@ class Bidi { static bool isRtlLanguage(String languageString) { return new RegExp(r'^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_]' r'(Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))' - r'($|-|_)', ignoreCase : true).hasMatch(languageString); + r'($|-|_)', caseSensitive: false).hasMatch(languageString); } /** @@ -401,4 +401,4 @@ class Bidi { static bool detectRtlDirectionality(String str, {bool isHtml: false}) { return estimateDirectionOfText(str, isHtml: isHtml) == TextDirection.RTL; } -} \ No newline at end of file +} diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart index 9168488f73c..e4a2d65572f 100644 --- a/pkg/intl/lib/date_format.dart +++ b/pkg/intl/lib/date_format.dart @@ -279,7 +279,7 @@ class DateFormat { * Returns a list of all locales for which we have date formatting * information. */ - static List allLocalesWithSymbols() => dateTimeSymbols.keys; + static List allLocalesWithSymbols() => dateTimeSymbols.keys.toList(); /** * The named constructors for this class are all conveniences for creating diff --git a/pkg/intl/lib/date_symbol_data_file.dart b/pkg/intl/lib/date_symbol_data_file.dart index 2a5e2004aa4..32a5cd431ce 100644 --- a/pkg/intl/lib/date_symbol_data_file.dart +++ b/pkg/intl/lib/date_symbol_data_file.dart @@ -9,6 +9,7 @@ library date_symbol_data_json; +import 'dart:async'; import "date_symbols.dart"; import "src/lazy_locale_data.dart"; import 'src/date_format_internal.dart'; @@ -41,4 +42,4 @@ Future initializeDateFormatting(String locale, String path) { /** Defines how new date symbol entries are created. */ DateSymbols _createDateSymbol(Map map) { return new DateSymbols.deserializeFromMap(map); -} \ No newline at end of file +} diff --git a/pkg/intl/lib/date_symbol_data_local.dart b/pkg/intl/lib/date_symbol_data_local.dart index 6474b5a0e29..939bb3df9ef 100644 --- a/pkg/intl/lib/date_symbol_data_local.dart +++ b/pkg/intl/lib/date_symbol_data_local.dart @@ -15,6 +15,9 @@ */ library date_symbol_data; + +import 'dart:async'; + import "date_symbols.dart"; import "src/date_format_internal.dart"; import "date_time_patterns.dart"; diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart index e2cd831abf8..9214b662a3a 100644 --- a/pkg/intl/lib/intl.dart +++ b/pkg/intl/lib/intl.dart @@ -16,6 +16,7 @@ */ library intl; +import 'dart:async'; import 'src/intl_helpers.dart'; import 'dart:math'; import 'date_symbols.dart'; @@ -127,7 +128,7 @@ class Intl { * will be extracted automatically but for the time being it must be passed * explicitly in the [name] and [args] arguments. */ - static String message(String message_str, {final String desc: '', + static Future message(String message_str, {final String desc: '', final Map examples: const {}, String locale, String name, List args}) { return messageLookup.lookupMessage( @@ -270,4 +271,4 @@ class Intl { if (_defaultLocale == null) _defaultLocale = systemLocale; return _defaultLocale; } -} \ No newline at end of file +} diff --git a/pkg/intl/lib/intl_standalone.dart b/pkg/intl/lib/intl_standalone.dart index d8ca238b828..cf2e4ef4f10 100644 --- a/pkg/intl/lib/intl_standalone.dart +++ b/pkg/intl/lib/intl_standalone.dart @@ -11,6 +11,7 @@ library intl_standalone; +import "dart:async"; import "dart:io"; import "intl.dart"; @@ -113,4 +114,4 @@ Future _checkResult(ProcessResult result, RegExp regex) { Future _setLocale(aLocale) { Intl.systemLocale = Intl.canonicalizedLocale(aLocale); return new Future.immediate(Intl.systemLocale); -} \ No newline at end of file +} diff --git a/pkg/intl/lib/message_lookup_local.dart b/pkg/intl/lib/message_lookup_local.dart index 9c62fb33f4b..e8a0e97ebb0 100644 --- a/pkg/intl/lib/message_lookup_local.dart +++ b/pkg/intl/lib/message_lookup_local.dart @@ -15,6 +15,7 @@ library message_lookup_local; +import 'dart:async'; import 'intl.dart'; import 'src/intl_helpers.dart'; import 'dart:mirrors'; @@ -88,13 +89,13 @@ class MessageLookupLocal { * will be extracted automatically but for the time being it must be passed * explicitly in the [name] and [args] arguments. */ - String lookupMessage(String message_str, [final String desc='', + Future lookupMessage(String message_str, [final String desc='', final Map examples=const {}, String locale, String name, List args]) { - if (name == null) return message_str; + if (name == null) return new Future.immediate(message_str); // The translations also make use of Intl.message, so we need to not // recurse and just stop when we find the first substitution. - if (_lookupInProgress) return message_str; + if (_lookupInProgress) return new Future.immediate(message_str); _lookupInProgress = true; var result; try { @@ -108,14 +109,15 @@ class MessageLookupLocal { onFailure: (locale)=>locale); LibraryMirror messagesForThisLocale = _libraries['$_sourcePrefix$verifiedLocale']; - if (messagesForThisLocale == null) return message_str; - MethodMirror localized = messagesForThisLocale.functions[name]; - if (localized == null) return message_str; - result = messagesForThisLocale.invoke(localized.simpleName, args); + if (messagesForThisLocale == null) { + return new Future.immediate(message_str); } - finally { + MethodMirror localized = messagesForThisLocale.functions[name]; + if (localized == null) return new Future.immediate(message_str); + result = messagesForThisLocale.invoke(localized.simpleName, args); + } finally { _lookupInProgress = false; } - return result.value.reflectee; + return result.then((value) => value.reflectee); } -} \ No newline at end of file +} diff --git a/pkg/intl/lib/src/date_format_internal.dart b/pkg/intl/lib/src/date_format_internal.dart index 55be76751aa..a5f48118500 100644 --- a/pkg/intl/lib/src/date_format_internal.dart +++ b/pkg/intl/lib/src/date_format_internal.dart @@ -13,6 +13,7 @@ */ library date_format_internal; +import 'dart:async'; import 'intl_helpers.dart'; import '../date_symbols.dart'; @@ -64,4 +65,4 @@ void initializeDatePatterns(Function patterns) { Future initializeIndividualLocaleDateFormatting(Function init) { return init(dateTimeSymbols, dateTimePatterns); -} \ No newline at end of file +} diff --git a/pkg/intl/lib/src/file_data_reader.dart b/pkg/intl/lib/src/file_data_reader.dart index 4448081eb55..1c0b4ad4426 100644 --- a/pkg/intl/lib/src/file_data_reader.dart +++ b/pkg/intl/lib/src/file_data_reader.dart @@ -9,6 +9,7 @@ library file_data_reader; +import 'dart:async'; import 'dart:io'; import 'intl_helpers.dart'; diff --git a/pkg/intl/lib/src/intl_helpers.dart b/pkg/intl/lib/src/intl_helpers.dart index 12c8395fd33..d431584fdea 100644 --- a/pkg/intl/lib/src/intl_helpers.dart +++ b/pkg/intl/lib/src/intl_helpers.dart @@ -10,6 +10,8 @@ library intl_helpers; import '../date_symbols.dart'; +import 'dart:async'; + /** * This is used as a marker for a locale data map that hasn't been initialized, * and will throw an exception on any usage that isn't the fallback @@ -61,4 +63,4 @@ void initializeInternalMessageLookup(Function lookupFunction) { if (messageLookup is UninitializedLocaleData) { messageLookup = lookupFunction(); } -} \ No newline at end of file +} diff --git a/pkg/intl/lib/src/lazy_locale_data.dart b/pkg/intl/lib/src/lazy_locale_data.dart index 66acbdf550b..a7ec331949b 100644 --- a/pkg/intl/lib/src/lazy_locale_data.dart +++ b/pkg/intl/lib/src/lazy_locale_data.dart @@ -9,9 +9,10 @@ */ library lazy_locale_data; +import 'dart:async'; import 'dart:uri'; import 'intl_helpers.dart'; -import 'dart:json'; +import 'dart:json' as json; /** * This implements the very basic map-type operations which are used @@ -99,7 +100,7 @@ class LazyLocaleData { */ Future initLocale(String localeName) { var data = _reader.read(localeName); - return jsonData(data).transform( (input) { + return jsonData(data).then( (input) { map[localeName] = _creationFunction(input);}); } @@ -108,6 +109,6 @@ class LazyLocaleData { * return another future that parses the JSON into a usable format. */ Future jsonData(Future input) { - return input.transform( (response) => JSON.parse(response)); + return input.then( (response) => json.parse(response)); } -} \ No newline at end of file +} diff --git a/pkg/intl/test/date_time_format_file_test_stub.dart b/pkg/intl/test/date_time_format_file_test_stub.dart index 6306bfbda2b..470a6d44a51 100644 --- a/pkg/intl/test/date_time_format_file_test_stub.dart +++ b/pkg/intl/test/date_time_format_file_test_stub.dart @@ -8,6 +8,7 @@ */ library date_time_format_file_test; +import 'dart:async'; import '../lib/intl.dart'; import '../lib/date_symbol_data_file.dart'; import 'dart:io'; diff --git a/pkg/intl/test/date_time_format_http_request_test.dart b/pkg/intl/test/date_time_format_http_request_test.dart index fb147b44097..2fb5d991428 100644 --- a/pkg/intl/test/date_time_format_http_request_test.dart +++ b/pkg/intl/test/date_time_format_http_request_test.dart @@ -25,8 +25,9 @@ main() { void runEverything(_) { // Initialize all locales and wait for them to finish before running tests. - var futures = DateFormat.allLocalesWithSymbols().map( - (locale) => initializeDateFormatting(locale, url)); + var futures = DateFormat.allLocalesWithSymbols() + .mappedBy((locale) => initializeDateFormatting(locale, url)) + .toList(); Futures.wait(futures).then(expectAsync1((_) { runDateTests(smallSetOfLocales()); shutDown();})); diff --git a/pkg/intl/test/date_time_format_local_test_stub.dart b/pkg/intl/test/date_time_format_local_test_stub.dart index 0556cd58664..6a5225d75ee 100644 --- a/pkg/intl/test/date_time_format_local_test_stub.dart +++ b/pkg/intl/test/date_time_format_local_test_stub.dart @@ -9,6 +9,7 @@ library date_time_format_test; +import 'dart:async'; import '../lib/intl.dart'; import '../lib/date_time_patterns.dart'; import '../lib/date_symbol_data_local.dart'; @@ -24,7 +25,8 @@ runWith([Function getSubset]) { void runEverything(Function getSubset) { // Initialize all locales and wait for them to finish before running tests. - var futures = DateFormat.allLocalesWithSymbols().map( - (locale) => initializeDateFormatting(locale, null)); + var futures = DateFormat.allLocalesWithSymbols() + .mappedBy((locale) => initializeDateFormatting(locale, null)) + .toList(); Futures.wait(futures).then((results) => runDateTests(getSubset())); } diff --git a/pkg/intl/test/date_time_format_test_core.dart b/pkg/intl/test/date_time_format_test_core.dart index f03e0265a95..c275f2910b2 100644 --- a/pkg/intl/test/date_time_format_test_core.dart +++ b/pkg/intl/test/date_time_format_test_core.dart @@ -158,7 +158,7 @@ testRoundTripParsing(String localeName, Date date) { DateFormat.ABBR_MONTH_WEEKDAY_DAY]; for(int i = 0; i < formatsToTest.length; i++) { var skeleton = formatsToTest[i]; - if (!badSkeletons.some((x) => x == skeleton)) { + if (!badSkeletons.any((x) => x == skeleton)) { var format = new DateFormat(skeleton, localeName); var actualResult = format.format(date); var parsed = format.parse(actualResult); @@ -177,7 +177,7 @@ List allLocales() => DateFormat.allLocalesWithSymbols(); */ List oddLocales() { int i = 1; - return allLocales().filter((x) => (i++).isOdd); + return allLocales().where((x) => (i++).isOdd).toList(); } /** @@ -193,7 +193,7 @@ List smallSetOfLocales() { */ List evenLocales() { int i = 1; - return allLocales().filter((x) => !((i++).isOdd)); + return allLocales().where((x) => !((i++).isOdd)).toList(); } // TODO(alanknight): Run specific tests for the en_ISO locale which isn't @@ -217,10 +217,14 @@ runDateTests([List subset]) { test('Basic date format parsing', () { var date_format = new DateFormat("d"); expect( - date_format.parsePattern("hh:mm:ss").map((x) => x.pattern), + date_format.parsePattern("hh:mm:ss") + .mappedBy((x) => x.pattern) + .toList(), orderedEquals(["hh",":", "mm",":","ss"])); expect( - date_format.parsePattern("hh:mm:ss").map((x) => x.pattern), + date_format.parsePattern("hh:mm:ss") + .mappedBy((x) => x.pattern) + .toList(), orderedEquals(["hh",":", "mm",":","ss"])); }); diff --git a/pkg/intl/test/intl_message_test.dart b/pkg/intl/test/intl_message_test.dart index 6d433cd4916..f8bcd5e32b2 100644 --- a/pkg/intl/test/intl_message_test.dart +++ b/pkg/intl/test/intl_message_test.dart @@ -25,13 +25,13 @@ runTests(_) { test('Trivial Message', () { hello() => Intl.message('Hello, world!', desc: 'hello world string'); - expect(hello(), equals('Hello, world!')); + expect(hello(), completion(equals('Hello, world!'))); }); test('Message with one parameter', () { lucky(number) => Intl.message('Your lucky number is $number', desc: 'number str', examples: {'number': 2}); - expect(lucky(3), equals('Your lucky number is 3')); + expect(lucky(3), completion(equals('Your lucky number is 3'))); }); test('Message with multiple plural cases (whole message)', () { @@ -42,9 +42,9 @@ runTests(_) { 'other': 'There are $number emails left.'}), desc: 'Message telling user how many emails will be sent.', examples: {'number': 32}); - expect(emails(5), equals('There are 5 emails left.')); - expect(emails(0), equals('There are no emails left.')); - expect(emails(1), equals('There is one email left.')); + expect(emails(5), completion(equals('There are 5 emails left.'))); + expect(emails(0), completion(equals('There are no emails left.'))); + expect(emails(1), completion(equals('There is one email left.'))); }); test('Message with multiple plural cases (partial message)', () { @@ -55,9 +55,9 @@ runTests(_) { 'other': 'are'})} $number messages left.", desc: 'Message telling user how many emails will be sent.', examples: {'number': 32}); - expect(emails(5), equals('There are 5 messages left.')); - expect(emails(0), equals('There are 0 messages left.')); - expect(emails(1), equals('There is 1 messages left.')); + expect(emails(5), completion(equals('There are 5 messages left.'))); + expect(emails(0), completion(equals('There are 0 messages left.'))); + expect(emails(1), completion(equals('There is 1 messages left.'))); }); test('Message with dictionary parameter', () { @@ -66,7 +66,7 @@ runTests(_) { desc: "States a person's name.", examples: {'first': 'Ford', 'last': 'Prefect'}); expect(hello({'first' : 'Ford', 'last' : 'Prefect'}), - equals('Hello, my name is Ford Prefect')); + completion(equals('Hello, my name is Ford Prefect'))); }); test('Message with object parameter', () { @@ -75,18 +75,19 @@ runTests(_) { desc: "States a person's name.", examples: {'first': 'Ford', 'last' : 'Prefect'}); var ford = new Person('Ford', 'Prefect'); - expect(hello(ford), equals('Hello, my name is Ford Prefect.')); + expect(hello(ford), completion(equals('Hello, my name is Ford Prefect.'))); }); test('WithLocale test', () { hello() => Intl.message('locale=${Intl.getCurrentLocale()}', desc: 'explains the locale'); - expect(Intl.withLocale('en-US', () => hello()), equals('locale=en-US')); + expect(Intl.withLocale('en-US', () => hello()), + completion(equals('locale=en-US'))); }); test('Test passing locale', () { hello(a_locale) => Intl.message('locale=${Intl.getCurrentLocale()}', desc: 'explains the locale', locale: a_locale); - expect(hello('en-US'), equals('locale=en_US')); + expect(hello('en-US'), completion(equals('locale=en_US'))); }); } diff --git a/pkg/intl/tool/generate_locale_data_files.dart b/pkg/intl/tool/generate_locale_data_files.dart index 81521f95594..b9999265972 100644 --- a/pkg/intl/tool/generate_locale_data_files.dart +++ b/pkg/intl/tool/generate_locale_data_files.dart @@ -17,7 +17,7 @@ import '../lib/date_symbol_data_local.dart'; import '../lib/date_time_patterns.dart'; import '../lib/intl.dart'; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; import '../test/data_directory.dart'; main() { @@ -68,10 +68,10 @@ void writeSymbols(locale, symbols) { void writePatterns(locale, patterns) { var file = new File('${dataDirectory}patterns/${locale}.json'); var outputStream = file.openOutputStream(); - outputStream.writeString(JSON.stringify(patterns)); + outputStream.writeString(json.stringify(patterns)); outputStream.close(); } void writeToJSON(dynamic data, OutputStream out) { - out.writeString(JSON.stringify(data.serializeToMap())); -} \ No newline at end of file + out.writeString(json.stringify(data.serializeToMap())); +} diff --git a/pkg/oauth2/lib/src/authorization_code_grant.dart b/pkg/oauth2/lib/src/authorization_code_grant.dart index dcb36d06f3d..5e9cbd2f6a1 100644 --- a/pkg/oauth2/lib/src/authorization_code_grant.dart +++ b/pkg/oauth2/lib/src/authorization_code_grant.dart @@ -4,6 +4,7 @@ library authorization_code_grant; +import 'dart:async'; import 'dart:uri'; // TODO(nweiz): This should be a "package:" import. See issue 6745. @@ -159,7 +160,7 @@ class AuthorizationCodeGrant { /// /// Throws [AuthorizationException] if the authorization fails. Future handleAuthorizationResponse(Map parameters) { - return async.chain((_) { + return async.then((_) { if (_state == _INITIAL_STATE) { throw new StateError( 'The authorization URL has not yet been generated.'); @@ -211,7 +212,7 @@ class AuthorizationCodeGrant { /// /// Throws [AuthorizationException] if the authorization fails. Future handleAuthorizationCode(String authorizationCode) { - return async.chain((_) { + return async.then((_) { if (_state == _INITIAL_STATE) { throw new StateError( 'The authorization URL has not yet been generated.'); @@ -238,7 +239,7 @@ class AuthorizationCodeGrant { // it be configurable? "client_id": this.identifier, "client_secret": this.secret - }).transform((response) { + }).then((response) { var credentials = handleAccessTokenResponse( response, tokenEndpoint, startTime, _scopes); return new Client( diff --git a/pkg/oauth2/lib/src/client.dart b/pkg/oauth2/lib/src/client.dart index a397c00fc01..fd315bb3fb9 100644 --- a/pkg/oauth2/lib/src/client.dart +++ b/pkg/oauth2/lib/src/client.dart @@ -4,6 +4,7 @@ library client; +import 'dart:async'; import 'dart:uri'; import '../../../http/lib/http.dart' as http; @@ -81,14 +82,14 @@ class Client extends http.BaseClient { /// will also automatically refresh this client's [Credentials] before sending /// the request if necessary. Future send(http.BaseRequest request) { - return async.chain((_) { + return async.then((_) { if (!credentials.isExpired) return new Future.immediate(null); if (!credentials.canRefresh) throw new ExpirationException(credentials); return refreshCredentials(); - }).chain((_) { + }).then((_) { request.headers['authorization'] = "Bearer ${credentials.accessToken}"; return _httpClient.send(request); - }).transform((response) { + }).then((response) { if (response.statusCode != 401 || !response.headers.containsKey('www-authenticate')) { return response; @@ -122,7 +123,7 @@ class Client extends http.BaseClient { /// [newScopes]. These must be a subset of the scopes in the /// [Credentials.scopes] field of [Client.credentials]. Future refreshCredentials([List newScopes]) { - return async.chain((_) { + return async.then((_) { if (!credentials.canRefresh) { var prefix = "OAuth credentials"; if (credentials.isExpired) prefix = "$prefix have expired and"; @@ -131,7 +132,7 @@ class Client extends http.BaseClient { return credentials.refresh(identifier, secret, newScopes: newScopes, httpClient: _httpClient); - }).transform((credentials) { + }).then((credentials) { _credentials = credentials; return this; }); diff --git a/pkg/oauth2/lib/src/credentials.dart b/pkg/oauth2/lib/src/credentials.dart index 89af7771182..12a0be8fd82 100644 --- a/pkg/oauth2/lib/src/credentials.dart +++ b/pkg/oauth2/lib/src/credentials.dart @@ -4,7 +4,8 @@ library credentials; -import 'dart:json'; +import 'dart:async'; +import 'dart:json' as JSON; import 'dart:uri'; import '../../../http/lib/http.dart' as http; @@ -152,7 +153,7 @@ class Credentials { if (httpClient == null) httpClient = new http.Client(); var startTime = new Date.now(); - return async.chain((_) { + return async.then((_) { if (refreshToken == null) { throw new StateError("Can't refresh credentials without a refresh " "token."); @@ -173,10 +174,10 @@ class Credentials { if (!scopes.isEmpty) fields["scope"] = Strings.join(scopes, ' '); return httpClient.post(tokenEndpoint, fields: fields); - }).transform((response) { + }).then((response) { return handleAccessTokenResponse( response, tokenEndpoint, startTime, scopes); - }).transform((credentials) { + }).then((credentials) { // The authorization server may issue a new refresh token. If it doesn't, // we should re-use the one we already have. if (credentials.refreshToken != null) return credentials; diff --git a/pkg/oauth2/lib/src/handle_access_token_response.dart b/pkg/oauth2/lib/src/handle_access_token_response.dart index cb08d8fd2e3..b80532d3f5a 100644 --- a/pkg/oauth2/lib/src/handle_access_token_response.dart +++ b/pkg/oauth2/lib/src/handle_access_token_response.dart @@ -5,7 +5,7 @@ library handle_access_token_response; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as JSON; import 'dart:uri'; import '../../../http/lib/http.dart' as http; diff --git a/pkg/oauth2/lib/src/utils.dart b/pkg/oauth2/lib/src/utils.dart index 59428b3c6fa..eb57e56260e 100644 --- a/pkg/oauth2/lib/src/utils.dart +++ b/pkg/oauth2/lib/src/utils.dart @@ -4,6 +4,7 @@ library utils; +import 'dart:async'; import 'dart:uri'; import 'dart:isolate'; import 'dart:crypto'; @@ -38,7 +39,7 @@ String mapToQuery(Map map) { value = (value == null || value.isEmpty) ? null : encodeUriComponent(value); pairs.add([key, value]); }); - return Strings.join(pairs.map((pair) { + return Strings.join(pairs.mappedBy((pair) { if (pair[1] == null) return pair[0]; return "${pair[0]}=${pair[1]}"; }), "&"); @@ -112,8 +113,4 @@ class AuthenticateHeader { } /// Returns a [Future] that asynchronously completes to `null`. -Future get async { - var completer = new Completer(); - new Timer(0, (_) => completer.complete(null)); - return completer.future; -} +Future get async => new Future.delayed(0, () => null); diff --git a/pkg/oauth2/test/authorization_code_grant_test.dart b/pkg/oauth2/test/authorization_code_grant_test.dart index 2b80cf4544f..e896dca25a2 100644 --- a/pkg/oauth2/test/authorization_code_grant_test.dart +++ b/pkg/oauth2/test/authorization_code_grant_test.dart @@ -30,6 +30,12 @@ void createGrant() { httpClient: client); } +void expectFutureThrows(future, predicate) { + future.catchError(expectAsync1((AsyncError e) { + expect(predicate(e.error), isTrue); + })); +} + void main() { group('.getAuthorizationUrl', () { setUp(createGrant); @@ -83,7 +89,8 @@ void main() { test("can't be called twice", () { grant.getAuthorizationUrl(redirectUrl); - expect(() => grant.getAuthorizationUrl(redirectUrl), throwsStateError); + expectFutureThrows(grant.getAuthorizationUrl(redirectUrl), + (e) => e is StateError); }); }); @@ -91,39 +98,44 @@ void main() { setUp(createGrant); test("can't be called before .getAuthorizationUrl", () { - expect(grant.handleAuthorizationResponse({}), throwsStateError); + expectFutureThrows(grant.handleAuthorizationResponse({}), + (e) => e is StateError); }); test("can't be called twice", () { grant.getAuthorizationUrl(redirectUrl); grant.handleAuthorizationResponse({'code': 'auth code'}); - expect(grant.handleAuthorizationResponse({'code': 'auth code'}), - throwsStateError); + expectFutureThrows( + grant.handleAuthorizationResponse({'code': 'auth code'}), + (e) => e is StateError); }); test('must have a state parameter if the authorization URL did', () { grant.getAuthorizationUrl(redirectUrl, state: 'state'); - expect(grant.handleAuthorizationResponse({'code': 'auth code'}), - throwsFormatException); + expectFutureThrows( + grant.handleAuthorizationResponse({'code': 'auth code'}), + (e) => e is FormatException); }); test('must have the same state parameter the authorization URL did', () { grant.getAuthorizationUrl(redirectUrl, state: 'state'); - expect(grant.handleAuthorizationResponse({ + expectFutureThrows(grant.handleAuthorizationResponse({ 'code': 'auth code', 'state': 'other state' - }), throwsFormatException); + }), (e) => e is FormatException); }); test('must have a code parameter', () { grant.getAuthorizationUrl(redirectUrl); - expect(grant.handleAuthorizationResponse({}), throwsFormatException); + expectFutureThrows(grant.handleAuthorizationResponse({}), + (e) => e is FormatException); }); test('with an error parameter throws an AuthorizationException', () { grant.getAuthorizationUrl(redirectUrl); - expect(grant.handleAuthorizationResponse({'error': 'invalid_request'}), - throwsAuthorizationException); + expectFutureThrows( + grant.handleAuthorizationResponse({'error': 'invalid_request'}), + (e) => e is AuthorizationException); }); test('sends an authorization code request', () { @@ -163,8 +175,8 @@ void main() { test("can't be called twice", () { grant.getAuthorizationUrl(redirectUrl); grant.handleAuthorizationCode('auth code'); - expect(grant.handleAuthorizationCode('auth code'), - throwsStateError); + expectFutureThrows(grant.handleAuthorizationCode('auth code'), + (e) => e is StateError); }); test('sends an authorization code request', () { diff --git a/pkg/oauth2/test/client_test.dart b/pkg/oauth2/test/client_test.dart index fba14a626e6..af8e7e47440 100644 --- a/pkg/oauth2/test/client_test.dart +++ b/pkg/oauth2/test/client_test.dart @@ -63,7 +63,7 @@ void main() { return new Future.immediate(new http.Response('good job', 200)); }); - expect(client.read(requestUri).transform((_) { + expect(client.read(requestUri).then((_) { expect(client.credentials.accessToken, equals('new access token')); }), completes); }); @@ -104,7 +104,7 @@ void main() { }), 200, headers: {'content-type': 'application/json'})); }); - expect(client.refreshCredentials().transform((_) { + expect(client.refreshCredentials().then((_) { expect(client.credentials.accessToken, equals('new access token')); }), completes); }); @@ -156,7 +156,7 @@ void main() { }); expect( - client.get(requestUri).transform((response) => response.statusCode), + client.get(requestUri).then((response) => response.statusCode), completion(equals(401))); }); @@ -178,7 +178,7 @@ void main() { }); expect( - client.get(requestUri).transform((response) => response.statusCode), + client.get(requestUri).then((response) => response.statusCode), completion(equals(401))); }); @@ -198,7 +198,7 @@ void main() { }); expect( - client.get(requestUri).transform((response) => response.statusCode), + client.get(requestUri).then((response) => response.statusCode), completion(equals(401))); }); @@ -218,7 +218,7 @@ void main() { }); expect( - client.get(requestUri).transform((response) => response.statusCode), + client.get(requestUri).then((response) => response.statusCode), completion(equals(401))); }); }); diff --git a/pkg/oauth2/test/credentials_test.dart b/pkg/oauth2/test/credentials_test.dart index 5faf2d04ce3..57e31a14939 100644 --- a/pkg/oauth2/test/credentials_test.dart +++ b/pkg/oauth2/test/credentials_test.dart @@ -4,8 +4,9 @@ library credentials_test; +import 'dart:async'; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as JSON; import 'dart:uri'; import '../../unittest/lib/unittest.dart'; @@ -43,15 +44,19 @@ void main() { var credentials = new oauth2.Credentials( 'access token', null, tokenEndpoint); expect(credentials.canRefresh, false); - expect(credentials.refresh('identifier', 'secret', httpClient: httpClient), - throwsStateError); + credentials.refresh('identifier', 'secret', httpClient: httpClient) + .catchError(expectAsync1((e) { + expect(e.error is StateError, isTrue); + })); }); test("can't refresh without a token endpoint", () { var credentials = new oauth2.Credentials('access token', 'refresh token'); expect(credentials.canRefresh, false); - expect(credentials.refresh('identifier', 'secret', httpClient: httpClient), - throwsStateError); + credentials.refresh('identifier', 'secret', httpClient: httpClient) + .catchError(expectAsync1((e) { + expect(e.error is StateError, isTrue); + })); }); test("can refresh with a refresh token and a token endpoint", () { @@ -79,7 +84,7 @@ void main() { expect(credentials.refresh('identifier', 'secret', httpClient: httpClient) - .transform((credentials) { + .then((credentials) { expect(credentials.accessToken, equals('new access token')); expect(credentials.refreshToken, equals('new refresh token')); }), completes); @@ -108,7 +113,7 @@ void main() { expect(credentials.refresh('identifier', 'secret', httpClient: httpClient) - .transform((credentials) { + .then((credentials) { expect(credentials.accessToken, equals('new access token')); expect(credentials.refreshToken, equals('refresh token')); }), completes); diff --git a/pkg/oauth2/test/handle_access_token_response_test.dart b/pkg/oauth2/test/handle_access_token_response_test.dart index 4757dc1b160..48465f2044a 100644 --- a/pkg/oauth2/test/handle_access_token_response_test.dart +++ b/pkg/oauth2/test/handle_access_token_response_test.dart @@ -5,7 +5,7 @@ library handle_access_token_response_test; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as JSON; import 'dart:uri'; import '../../unittest/lib/unittest.dart'; diff --git a/pkg/oauth2/test/utils.dart b/pkg/oauth2/test/utils.dart index 631ea954751..cf5bff26f3c 100644 --- a/pkg/oauth2/test/utils.dart +++ b/pkg/oauth2/test/utils.dart @@ -4,6 +4,8 @@ library utils; +import 'dart:async'; + import '../../unittest/lib/unittest.dart'; import '../../http/lib/http.dart' as http; import '../../http/lib/testing.dart'; diff --git a/pkg/path/lib/path.dart b/pkg/path/lib/path.dart index 99eee7be878..cc882f47f94 100644 --- a/pkg/path/lib/path.dart +++ b/pkg/path/lib/path.dart @@ -356,7 +356,7 @@ class Builder { List split(String path) { var parsed = _parse(path); // Filter out empty parts that exist due to multiple separators in a row. - parsed.parts = parsed.parts.filter((part) => part != ''); + parsed.parts = parsed.parts.where((part) => !part.isEmpty).toList(); if (parsed.root != null) parsed.parts.insertRange(0, 1, parsed.root); return parsed.parts; } diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart index b5d10744040..2b1377280a3 100644 --- a/pkg/serialization/lib/serialization.dart +++ b/pkg/serialization/lib/serialization.dart @@ -149,7 +149,8 @@ library serialization; import 'src/mirrors_helpers.dart'; import 'src/serialization_helpers.dart'; -import 'dart:json' show JSON; +import 'dart:async'; +import 'dart:json' as json; part 'src/reader_writer.dart'; part 'src/serialization_rule.dart'; @@ -201,7 +202,7 @@ class Serialization { */ bool get selfDescribing { if (_selfDescribing != null) return _selfDescribing; - return !_rules.some((x) => x is CustomRule); + return !_rules.any((x) => x is CustomRule); } /** @@ -362,8 +363,8 @@ class Serialization { target = object; candidateRules = _rules; } - List applicable = candidateRules.filter( - (each) => each.appliesTo(target, w)); + List applicable = + candidateRules.where((each) => each.appliesTo(target, w)).toList(); if (applicable.isEmpty) { return [addRuleFor(target)]; @@ -371,8 +372,8 @@ class Serialization { if (applicable.length == 1) return applicable; var first = applicable[0]; - var finalRules = applicable.filter( - (x) => !x.mustBePrimary || (x == first)); + var finalRules = applicable.where( + (x) => !x.mustBePrimary || (x == first)).toList(); if (finalRules.isEmpty) throw new SerializationException( 'No valid rule found for object $object'); @@ -436,4 +437,4 @@ class Serialization { class SerializationException implements Exception { final String message; const SerializationException([this.message]); -} \ No newline at end of file +} diff --git a/pkg/serialization/lib/src/basic_rule.dart b/pkg/serialization/lib/src/basic_rule.dart index 5289a8789dd..40c5f601f5d 100644 --- a/pkg/serialization/lib/src/basic_rule.dart +++ b/pkg/serialization/lib/src/basic_rule.dart @@ -239,14 +239,17 @@ class BasicRule extends SerializationRule { * Or, in the special case of null, two nulls. */ pullStateFrom(Iterator stream) { - var dataLength = stream.next(); + stream.moveNext(); + var dataLength = stream.current; var ruleData = new List(); for (var i = 0; i < dataLength; i++) { var subList = new List(); ruleData.add(subList); for (var j = 0; j < fields.length; j++) { - var a = stream.next(); - var b = stream.next(); + stream.moveNext(); + var a = stream.current; + stream.moveNext(); + var b = stream.current; if (!(a is int)) { // This wasn't a reference, so just use the first object as a literal. // particularly used for the case of null. @@ -360,7 +363,10 @@ class _NamedField extends _Field { setter(object, value); } - valueIn(InstanceMirror mirror) => mirror.getField(name).value.reflectee; + valueIn(InstanceMirror mirror) { + var futureValue = deprecatedFutureValue(mirror.getField(name)); + return futureValue.reflectee; + } /** Return the function to use to set our value. */ Function get setter => @@ -404,7 +410,7 @@ class _ConstantField extends _Field { * are kept in a separate object, which also has the ability to compute the * default fields to use reflectively. */ -class _FieldList implements Iterable { +class _FieldList extends Iterable { /** * All of our fields, indexed by name. Note that the names are not * necessarily strings. @@ -472,12 +478,12 @@ class _FieldList implements Iterable { void addAllNotExplicitlyExcluded(List aCollection) { if (aCollection == null) return; var names = aCollection; - names = names.filter((x) => !_excludeFields.contains(x)); + names = names.where((x) => !_excludeFields.contains(x)); addAllByName(names); } /** Add all the fields with the given names without any special properties. */ - void addAllByName(List names) { + void addAllByName(Iterable names) { for (var each in names) { allFields.putIfAbsent(each, () => new _Field(each, this)); } @@ -493,7 +499,7 @@ class _FieldList implements Iterable { contents; } - Iterator iterator() => contents.iterator(); + Iterator get iterator => contents.iterator; /** Return a cached, sorted list of all the fields. */ List<_Field> get contents { @@ -524,11 +530,16 @@ class _FieldList implements Iterable { } List get constructorFields => _constructorFields; - List constructorFieldNames() => constructorFields.map((x) => x.name); - List constructorFieldIndices() => constructorFields.map((x) => x.index); - List regularFields() => contents.filter((x) => !x.usedInConstructor); - List regularFieldNames() => regularFields().map((x) => x.name); - List regularFieldIndices() => regularFields().map((x) => x.index); + List constructorFieldNames() => + constructorFields.mappedBy((x) => x.name).toList(); + List constructorFieldIndices() => + constructorFields.mappedBy((x) => x.index).toList(); + List regularFields() => + contents.where((x) => !x.usedInConstructor).toList(); + List regularFieldNames() => + regularFields().mappedBy((x) => x.name).toList(); + List regularFieldIndices() => + regularFields().mappedBy((x) => x.index).toList(); /** @@ -539,16 +550,16 @@ class _FieldList implements Iterable { */ void figureOutFields() { List names(Collection mirrors) => - mirrors.map((each) => each.simpleName); + mirrors.mappedBy((each) => each.simpleName).toList(); if (!_shouldFigureOutFields || !regularFields().isEmpty) return; var fields = publicFields(mirror); var getters = publicGetters(mirror); - var gettersWithSetters = getters.filter( (each) - => mirror.setters["${each.simpleName}="] != null); - var gettersThatMatchConstructor = getters.filter((each) + var gettersWithSetters = getters.where( (each) + => mirror.setters["${each.simpleName}="] != null).toList(); + var gettersThatMatchConstructor = getters.where((each) => (named(each.simpleName) != null) && - (named(each.simpleName).usedInConstructor)); + (named(each.simpleName).usedInConstructor)).toList(); addAllNotExplicitlyExcluded(names(fields)); addAllNotExplicitlyExcluded(names(gettersWithSetters)); addAllNotExplicitlyExcluded(names(gettersThatMatchConstructor)); @@ -594,10 +605,11 @@ class Constructor { */ constructFrom(state, Reader r) { // TODO(alanknight): Handle named parameters - Collection inflated = fieldNumbers.map( - (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)); + Collection inflated = fieldNumbers.mappedBy( + (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x)) + .toList(); var result = type.newInstance(name, inflated); - return result.value; + return deprecatedFutureValue(result); } } @@ -616,4 +628,4 @@ class _MapWrapper { get length => _map.length; asMap() => _map; -} \ No newline at end of file +} diff --git a/pkg/serialization/lib/src/mirrors_helpers.dart b/pkg/serialization/lib/src/mirrors_helpers.dart index b67eccac8bc..ef849257dc8 100644 --- a/pkg/serialization/lib/src/mirrors_helpers.dart +++ b/pkg/serialization/lib/src/mirrors_helpers.dart @@ -18,7 +18,7 @@ import 'serialization_helpers.dart'; * fields. */ List publicFields(ClassMirror mirror) { - var mine = mirror.variables.values.filter( + var mine = mirror.variables.values.where( (x) => !(x.isPrivate || x.isStatic)); var mySuperclass = mirror.superclass; if (mySuperclass != mirror) { @@ -42,13 +42,13 @@ bool hasField(String name, ClassMirror mirror) { * Return a list of all the getters of a class, including inherited * getters. Note that this allows private getters, but excludes statics. */ -List publicGetters(ClassMirror mirror) { - var mine = mirror.getters.values.filter((x) => !(x.isPrivate || x.isStatic)); +Iterable publicGetters(ClassMirror mirror) { + var mine = mirror.getters.values.where((x) => !(x.isPrivate || x.isStatic)); var mySuperclass = mirror.superclass; if (mySuperclass != mirror) { return append(publicGetters(mirror.superclass), mine); } else { - return mine; + return mine.toList(); } } @@ -67,8 +67,8 @@ bool hasGetter(String name, ClassMirror mirror) { */ List publicGettersWithMatchingSetters(ClassMirror mirror) { var setters = mirror.setters; - return publicGetters(mirror).filter((each) => - setters["${each.simpleName}="] != null); + return publicGetters(mirror).where((each) => + setters["${each.simpleName}="] != null).toList(); } /** @@ -76,4 +76,4 @@ List publicGettersWithMatchingSetters(ClassMirror mirror) { * as literals, so we have to be passed an instance and then extract a * ClassMirror from that. Given a horrible name as an extra reminder to fix it. */ -ClassMirror turnInstanceIntoSomethingWeCanUse(x) => reflect(x).type; \ No newline at end of file +ClassMirror turnInstanceIntoSomethingWeCanUse(x) => reflect(x).type; diff --git a/pkg/serialization/lib/src/reader_writer.dart b/pkg/serialization/lib/src/reader_writer.dart index ffda2096257..8892aa71698 100644 --- a/pkg/serialization/lib/src/reader_writer.dart +++ b/pkg/serialization/lib/src/reader_writer.dart @@ -226,7 +226,7 @@ class Writer { * our custom JSON format. */ String toStringFormat() { - return JSON.stringify(toMaps()); + return json.stringify(toMaps()); } /** @@ -260,7 +260,7 @@ class Writer { * stored in the output under "roots" in the default format. */ _rootReferences(roots) => - roots.map(_referenceFor); + roots.mappedBy(_referenceFor).toList(); /** * Given an object, return a reference for it if one exists. If there's @@ -369,7 +369,7 @@ class Reader { // When we set the data, initialize the object storage to a matching size. void set data(List newData) { _data = newData; - objects = _data.map((x) => new List(x.length)); + objects = _data.mappedBy((x) => new List(x.length)).toList(); } /** @@ -379,7 +379,7 @@ class Reader { */ read(String input, [Map externals = const {}]) { namedObjects = externals; - var topLevel = JSON.parse(input); + var topLevel = json.parse(input); var ruleString = topLevel["rules"]; readRules(ruleString, externals); data = topLevel["data"]; @@ -415,7 +415,7 @@ class Reader { var ruleString = topLevel[0]; readRules(ruleString, externals); var flatData = topLevel[1]; - var stream = flatData.iterator(); + var stream = flatData.iterator; var tempData = new List(rules.length); for (var eachRule in rules) { tempData[eachRule.number] = eachRule.pullStateFrom(stream); @@ -425,10 +425,13 @@ class Reader { inflateForRule(eachRule); } var rootsAsInts = topLevel[2]; - var rootStream = rootsAsInts.iterator(); + var rootStream = rootsAsInts.iterator; var roots = new List(); - while (rootStream.hasNext) { - roots.add(new Reference(this, rootStream.next(), rootStream.next())); + while (rootStream.moveNext()) { + var first = rootStream.current; + rootStream.moveNext(); + var second = rootStream.current; + roots.add(new Reference(this, first, second)); } var x = inflateReference(roots[0]); return inflateReference(roots.first); @@ -646,5 +649,5 @@ class DesignatedRuleForObject { DesignatedRuleForObject(this.target, this.rulePredicate); - possibleRules(List rules) => rules.filter(rulePredicate); + possibleRules(List rules) => rules.where(rulePredicate).toList(); } diff --git a/pkg/serialization/lib/src/serialization_helpers.dart b/pkg/serialization/lib/src/serialization_helpers.dart index 335bc0d4752..407c6562d2b 100644 --- a/pkg/serialization/lib/src/serialization_helpers.dart +++ b/pkg/serialization/lib/src/serialization_helpers.dart @@ -18,7 +18,7 @@ doNothing(x) => x; /** Concatenate two lists. Handle the case where one or both might be null. */ // TODO(alanknight): Remove once issue 5342 is resolved. -List append(List a, List b) { +List append(Iterable a, Iterable b) { if (a == null) { return (b == null) ? [] : new List.from(b); } @@ -29,11 +29,11 @@ List append(List a, List b) { } /** - * Return a sorted version of [aCollection], using the default sort criterion. - * Always returns a List, regardless of the type of [aCollection]. + * Return a sorted version of [anIterable], using the default sort criterion. + * Always returns a List, regardless of the type of [anIterable]. */ -List sorted(aCollection) { - var result = new List.from(aCollection); +List sorted(anIterable) { + var result = new List.from(anIterable); result.sort(); return result; } @@ -105,9 +105,10 @@ class MapLikeIterableForList extends MapLikeIterable { MapLikeIterableForList(collection) : super(collection); void forEach(f) { - Iterator iterator = collection.iterator(); + Iterator iterator = collection.iterator; for (var i = 0; i < collection.length; i++) { - f(i, iterator.next()); + iterator.moveNext(); + f(i, iterator.current); } } @@ -129,6 +130,13 @@ values(x) { throw new ArgumentError("Invalid argument"); } +mapValues(x, f) { + if (x is Set) return x.mappedBy(f).toSet(); + if (x is Iterable) return x.mappedBy(f).toList(); + if (x is Map) return new ListLikeIterable(x).map(f); + throw new ArgumentError("Invalid argument"); +} + /** * A class for iterating over things as if they were Lists, which primarily * means that forEach passes one argument, and map() returns a new Map @@ -159,7 +167,7 @@ class ListLikeIterable { /** * Return an iterator that behaves like a List iterator, taking one parameter. */ - Iterator iterator() => collection.values.iterator(); + Iterator get iterator => collection.values.iterator; } /** diff --git a/pkg/serialization/lib/src/serialization_rule.dart b/pkg/serialization/lib/src/serialization_rule.dart index 46f9c57377e..d0228465d64 100644 --- a/pkg/serialization/lib/src/serialization_rule.dart +++ b/pkg/serialization/lib/src/serialization_rule.dart @@ -150,16 +150,19 @@ abstract class SerializationRule { * iterator in a flat format. */ pullStateFrom(Iterator stream) { - var numberOfEntries = stream.next(); + stream.moveNext(); + var numberOfEntries = stream.current; var ruleData = new List(); for (var i = 0; i < numberOfEntries; i++) { var subLength = dataLengthIn(stream); var subList = []; ruleData.add(subList); for (var j = 0; j < subLength; j++) { - var a = stream.next(); - var b = stream.next(); - if (!(a is int)) { + stream.moveNext(); + var a = stream.current; + stream.moveNext(); + var b = stream.current; + if (a is! int) { // This wasn't a reference, just use the first object as a literal. // particularly used for the case of null. subList.add(a); @@ -174,11 +177,11 @@ abstract class SerializationRule { /** * Return the length of the list of data we expect to see on a particular * iterator in a flat format. This may have been encoded in the stream if we - * are variable length, or it may be constant. Note that this is expressed in - * + * are variable length, or it may be constant. Returns null if the [Iterator] + * is empty. */ dataLengthIn(Iterator stream) => - writeLengthInFlatFormat ? stream.next() : dataLength; + writeLengthInFlatFormat ? (stream..moveNext()).current : dataLength; /** * If the data is fixed length, return it here. Unused in the non-flat @@ -231,15 +234,19 @@ class ListRule extends SerializationRule { // TODO(alanknight): This is much too close to the basicRule implementation, // and I'd refactor them if I didn't think this whole mechanism needed to // change soon. - var length = stream.next(); + stream.moveNext(); + var length = stream.current; var ruleData = new List(); for (var i = 0; i < length; i++) { - var subLength = stream.next(); + stream.moveNext(); + var subLength = stream.current; var subList = new List(); ruleData.add(subList); for (var j = 0; j < subLength; j++) { - var a = stream.next(); - var b = stream.next(); + stream.moveNext(); + var a = stream.current; + stream.moveNext(); + var b = stream.current; if (!(a is int)) { // This wasn't a reference, just use the first object as a literal. // particularly used for the case of null. @@ -320,10 +327,12 @@ class PrimitiveRule extends SerializationRule { * indicating the number of objects and then N simple objects. */ pullStateFrom(Iterator stream) { - var length = stream.next(); + stream.moveNext(); + var length = stream.current; var ruleData = new List(); for (var i = 0; i < length; i++) { - ruleData.add(stream.next()); + stream.moveNext(); + ruleData.add(stream.current); } return ruleData; } @@ -487,7 +496,7 @@ abstract class CustomRule extends SerializationRule { /** Create a lazy list/map that will inflate its items on demand in [r]. */ _lazy(l, Reader r) { - if (l is List) return new _LazyList(l, r); + if (l is List) return l.mappedBy(r.inflateReference); if (l is Map) return new _LazyMap(l, r); throw new SerializationException("Invalid type: must be Map or List - $l"); } @@ -510,14 +519,14 @@ class _LazyMap implements Map { int get length => _raw.length; bool get isEmpty => _raw.isEmpty; - List get keys => _raw.keys; + Iterable get keys => _raw.keys; bool containsKey(x) => _raw.containsKey(x); // These operations will work, but may be expensive, and are probably // best avoided. get _inflated => keysAndValues(_raw).map(_reader.inflateReference); bool containsValue(x) => _inflated.containsValue(x); - List get values => _inflated.values; + Iterable get values => _inflated.values; void forEach(f) => _inflated.forEach(f); // These operations are all invalid @@ -527,55 +536,3 @@ class _LazyMap implements Map { remove(x) => _throw(); clear() => _throw(); } - -/** - * This provides an implementation of List that wraps a list which may - * contain references to (potentially) non-inflated objects. If these - * are accessed it will inflate them. This allows us to pass something that - * looks like it's just a list of objects to a [CustomRule] without needing - * to inflate all the references in advance. - */ -class _LazyList implements List { - _LazyList(this._raw, this._reader); - - List _raw; - Reader _reader; - - // This is the only operation that really matters. - operator [](x) => _reader.inflateReference(_raw[x]); - - int get length => _raw.length; - bool get isEmpty => _raw.isEmpty; - get first => _reader.inflateReference(_raw.first); - get last => _reader.inflateReference(_raw.last); - - // These operations will work, but may be expensive, and are probably - // best avoided. - get _inflated => _raw.map(_reader.inflateReference); - map(f) => _inflated.map(f); - filter(f) => _inflated.filter(f); - bool contains(element) => _inflated.filter(element); - forEach(f) => _inflated.forEach(f); - reduce(x, f) => _inflated.reduce(x, f); - every(f) => _inflated(f); - some(f) => _inflated(f); - iterator() => _inflated.iterator(); - indexOf(x, [pos = 0]) => _inflated.indexOf(x); - lastIndexOf(x, [pos]) => _inflated.lastIndexOf(x); - - // These operations are all invalid - _throw() => throw new UnsupportedError("Not modifiable"); - operator []=(x, y) => _throw(); - add(x) => _throw(); - addLast(x) => _throw(); - addAll(x) => _throw(); - sort([f]) => _throw(); - clear() => _throw(); - removeAt(x) => _throw(); - removeLast() => _throw(); - getRange(x, y) => _throw(); - setRange(x, y, z, [a]) => _throw(); - removeRange(x, y) => _throw(); - insertRange(x, y, [z]) => _throw(); - void set length(x) => _throw(); -} \ No newline at end of file diff --git a/pkg/serialization/test/serialization_test.dart b/pkg/serialization/test/serialization_test.dart index 3a165944372..dcd8a56dea7 100644 --- a/pkg/serialization/test/serialization_test.dart +++ b/pkg/serialization/test/serialization_test.dart @@ -192,7 +192,7 @@ main() { var trace = new Trace(new Writer(s)); trace.writer.trace = trace; trace.trace(n1); - var all = trace.writer.references.keys; + var all = trace.writer.references.keys.toSet(); expect(all.length, 4); expect(all.contains(n1), isTrue); expect(all.contains(n2), isTrue); @@ -207,7 +207,7 @@ main() { w.write(n1); expect(w.states.length, 4); // prims, lists, essential lists, basic var children = 0, name = 1, parent = 2; - List rootNode = w.states[3].filter((x) => x[name] == "1"); + List rootNode = w.states[3].where((x) => x[name] == "1").toList(); rootNode = rootNode.first; expect(rootNode[parent], isNull); var list = w.states[1].first; @@ -490,7 +490,7 @@ runRoundTripTestFlat(serializerSetUp) { /** Extract the state from [object] using the rules in [s] and return it. */ states(object, Serialization s) { var rules = s.rulesFor(object, null); - return rules.map((x) => x.extractState(object, doNothing)); + return rules.mappedBy((x) => x.extractState(object, doNothing)).toList(); } /** A hard-coded rule for serializing Node instances. */ @@ -502,4 +502,4 @@ class NodeRule extends CustomRule { node.parent = state[0]; node.children = state[2]; } -} \ No newline at end of file +} diff --git a/pkg/unittest/lib/html_enhanced_config.dart b/pkg/unittest/lib/html_enhanced_config.dart index faad8eb8fae..a59078d7e21 100644 --- a/pkg/unittest/lib/html_enhanced_config.dart +++ b/pkg/unittest/lib/html_enhanced_config.dart @@ -172,10 +172,11 @@ class HtmlEnhancedConfiguration extends Configuration { previousGroup = test_.currentGroup; - var testsInGroup = results.filter( - (TestCase t) => t.currentGroup == previousGroup); + var testsInGroup = results + .where((TestCase t) => t.currentGroup == previousGroup) + .toList(); var groupTotalTestCount = testsInGroup.length; - var groupTestPassedCount = testsInGroup.filter( + var groupTestPassedCount = testsInGroup.where( (TestCase t) => t.result == 'pass').length; groupPassFail = groupTotalTestCount == groupTestPassedCount; var passFailClass = "unittest-group-status unittest-group-" diff --git a/pkg/unittest/lib/matcher.dart b/pkg/unittest/lib/matcher.dart index 83d6d03ce74..65583af227b 100644 --- a/pkg/unittest/lib/matcher.dart +++ b/pkg/unittest/lib/matcher.dart @@ -12,6 +12,8 @@ */ library matcher; +import 'dart:async'; + part 'src/basematcher.dart'; part 'src/collection_matchers.dart'; part 'src/core_matchers.dart'; diff --git a/pkg/unittest/lib/mock.dart b/pkg/unittest/lib/mock.dart index bf9d1bd545d..d1a98d7dcc3 100644 --- a/pkg/unittest/lib/mock.dart +++ b/pkg/unittest/lib/mock.dart @@ -844,8 +844,9 @@ class LogEntryList { remainingCount = logs.length; } - var keyIterator = keys.logs.iterator(); - LogEntry keyEntry = keyIterator.next(); + var keyIterator = keys.logs.iterator; + keyIterator.moveNext(); + LogEntry keyEntry = keyIterator.current; MatchState matchState = new MatchState(); for (LogEntry logEntry in logs) { @@ -869,8 +870,8 @@ class LogEntryList { if (includeKeys) { rtn.logs.add(keyEntry); } - if (keyIterator.hasNext) { - keyEntry = keyIterator.next(); + if (keyIterator.moveNext()) { + keyEntry = keyIterator.current; } else if (isPreceding) { // We're done. break; } @@ -1460,7 +1461,7 @@ class Mock { if (name == null) { // This log is not shared. log.logs.clear(); } else { // This log may be shared. - log.logs = log.logs.filter((e) => e.mockName != name); + log.logs = log.logs.where((e) => e.mockName != name).toList(); } } } diff --git a/pkg/unittest/lib/src/collection_matchers.dart b/pkg/unittest/lib/src/collection_matchers.dart index db13658b19b..b261226948d 100644 --- a/pkg/unittest/lib/src/collection_matchers.dart +++ b/pkg/unittest/lib/src/collection_matchers.dart @@ -63,7 +63,7 @@ class _SomeElement extends _CollectionMatcher { _SomeElement(this._matcher); bool matches(item, MatchState matchState) { - return item.some( (e) => _matcher.matches(e, matchState) ); + return item.any((e) => _matcher.matches(e, matchState)); } Description describe(Description description) => @@ -143,7 +143,7 @@ class _UnorderedEquals extends BaseMatcher { } else if (expectedLength < actualLength) { return 'has too many elements (${actualLength} > ${expectedLength})'; } - List matched = new List(actualLength); + List matched = new List.fixedLength(actualLength); for (var i = 0; i < actualLength; i++) { matched[i] = false; } diff --git a/pkg/unittest/lib/src/config.dart b/pkg/unittest/lib/src/config.dart index e3a788ea153..85398ae497a 100644 --- a/pkg/unittest/lib/src/config.dart +++ b/pkg/unittest/lib/src/config.dart @@ -132,6 +132,7 @@ class Configuration { _receivePort.close(); if (success) { _postMessage('unittest-suite-success'); + _receivePort.close(); } else { throw new Exception('Some tests failed.'); } @@ -141,7 +142,7 @@ class Configuration { // TODO(nweiz): Use this simpler code once issue 2980 is fixed. // return str.replaceAll(new RegExp("^", multiLine: true), " "); - return Strings.join(str.split("\n").map((line) => " $line"), "\n"); + return Strings.join(str.split("\n").mappedBy((line) => " $line"), "\n"); } /** Handle errors that happen outside the tests. */ diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart index 3846fdd1810..7855ed92070 100644 --- a/pkg/unittest/lib/src/core_matchers.dart +++ b/pkg/unittest/lib/src/core_matchers.dart @@ -98,15 +98,15 @@ class _DeepMatcher extends BaseMatcher { if (actual is !Iterable) { return 'is not Iterable'; } - var expectedIterator = expected.iterator(); - var actualIterator = actual.iterator(); + var expectedIterator = expected.iterator; + var actualIterator = actual.iterator; var position = 0; String reason = null; while (reason == null) { - if (expectedIterator.hasNext) { - if (actualIterator.hasNext) { - Description r = matcher(expectedIterator.next(), - actualIterator.next(), + if (expectedIterator.moveNext()) { + if (actualIterator.moveNext()) { + Description r = matcher(expectedIterator.current, + actualIterator.current, 'mismatch at position ${position}', depth); if (r != null) reason = r.toString(); @@ -114,7 +114,7 @@ class _DeepMatcher extends BaseMatcher { } else { reason = 'shorter than expected'; } - } else if (actualIterator.hasNext) { + } else if (actualIterator.moveNext()) { reason = 'longer than expected'; } else { return null; @@ -284,20 +284,20 @@ class Throws extends BaseMatcher { if (item is Future) { // Queue up an asynchronous expectation that validates when the future // completes. - item.onComplete(wrapAsync((future) { - if (future.hasValue) { - expect(false, isTrue, reason: - "Expected future to fail, but succeeded with '${future.value}'."); - } else if (_matcher != null) { - var reason; - if (future.stackTrace != null) { - var stackTrace = future.stackTrace.toString(); - stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}"; - reason = "Actual exception trace:\n$stackTrace"; - } - expect(future.exception, _matcher, reason: reason); + item.then((value) { + expect(false, isTrue, reason: + "Expected future to fail, but succeeded with '$value'."); + }); + + item.catchError((e) { + var reason; + if (e.stackTrace != null) { + var stackTrace = e.stackTrace.toString(); + stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}"; + reason = "Actual exception trace:\n$stackTrace"; } - })); + expect(e.error, _matcher, reason: reason); + }); // It hasn't failed yet. return true; @@ -573,9 +573,9 @@ class _Contains extends BaseMatcher { return item.indexOf(_expected) >= 0; } else if (item is Collection) { if (_expected is Matcher) { - return item.some((e) => _expected.matches(e, matchState)); + return item.any((e) => _expected.matches(e, matchState)); } else { - return item.some((e) => e == _expected); + return item.any((e) => e == _expected); } } else if (item is Map) { return item.containsKey(_expected); @@ -603,7 +603,7 @@ class _In extends BaseMatcher { if (_expected is String) { return _expected.indexOf(item) >= 0; } else if (_expected is Collection) { - return _expected.some((e) => e == item); + return _expected.any((e) => e == item); } else if (_expected is Map) { return _expected.containsKey(item); } diff --git a/pkg/unittest/lib/src/future_matchers.dart b/pkg/unittest/lib/src/future_matchers.dart index ce7e8043402..9154c7c1b72 100644 --- a/pkg/unittest/lib/src/future_matchers.dart +++ b/pkg/unittest/lib/src/future_matchers.dart @@ -35,18 +35,20 @@ class _Completes extends BaseMatcher { bool matches(item, MatchState matchState) { if (item is! Future) return false; - item.onComplete(wrapAsync((future) { + item.then((value) { + if (_matcher != null) expect(value, _matcher); + }); + + item.catchError((e) { var reason = 'Expected future to complete successfully, but it failed ' - 'with ${future.exception}'; + 'with ${e.error}'; if (future.stackTrace != null) { - var stackTrace = future.stackTrace.toString(); + var stackTrace = e.stackTrace.toString(); stackTrace = ' ${stackTrace.replaceAll('\n', '\n ')}'; reason = '$reason\nStack trace:\n$stackTrace'; } - - expect(future.hasValue, isTrue, reason: reason); - if (_matcher != null) expect(future.value, _matcher); - })); + expect(false, isTrue, reason: reason); + }); return true; } diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart index 25d965ecd4d..c615b123405 100644 --- a/pkg/unittest/lib/unittest.dart +++ b/pkg/unittest/lib/unittest.dart @@ -147,6 +147,7 @@ */ library unittest; +import 'dart:async'; import 'dart:isolate'; import 'matcher.dart'; export 'matcher.dart'; @@ -736,7 +737,7 @@ void filterTests(testFilter) { } else if (testFilter is Function) { filterFunction = testFilter; } - _tests = _tests.filter(filterFunction); + _tests = _tests.where(filterFunction).toList(); } /** Runs all queued tests, one at a time. */ diff --git a/pkg/webdriver/lib/webdriver.dart b/pkg/webdriver/lib/webdriver.dart index 8291db842d1..0dbbae4dbb4 100644 --- a/pkg/webdriver/lib/webdriver.dart +++ b/pkg/webdriver/lib/webdriver.dart @@ -4,10 +4,9 @@ library webdriver; -import 'dart:json'; +import 'dart:json' as json; import 'dart:uri'; import 'dart:io'; -import 'dart:math'; part 'src/base64decoder.dart'; @@ -207,7 +206,7 @@ class WebDriverBase { _path = matches[2]; var idx = _host.indexOf(':'); if (idx >= 0) { - _port = parseInt(_host.substring(idx+1)); + _port = int.parse(_host.substring(idx+1)); _host = _host.substring(0, idx); } else { _port = 80; @@ -241,7 +240,7 @@ class WebDriverBase { throw new Exception( 'The http method called for ${command} is ${http_method} but it has ' 'to be POST if you want to pass the JSON params ' - '${JSON.stringify(params)}'); + '${json.stringify(params)}'); } var path = command; @@ -258,7 +257,7 @@ class WebDriverBase { HttpHeaders.CONTENT_TYPE, 'application/json;charset=UTF-8'); OutputStream s = r.outputStream; if (params != null && params is Map) { - s.writeString(JSON.stringify(params)); + s.writeString(json.stringify(params)); } s.close(); }; @@ -282,7 +281,7 @@ class WebDriverBase { var value = null; results = sbuf.toString().trim(); // For some reason we get a bunch of NULs on the end - // of the text and the JSON parser blows up on these, so + // of the text and the json.parse blows up on these, so // strip them. We have to do this the hard way as // replaceAll('\0', '') does not work. // These NULs can be seen in the TCP packet, so it is not @@ -301,7 +300,7 @@ class WebDriverBase { if (status == 0 && results.length > 0) { // 4xx responses send plain text; others send JSON. if (r.statusCode < 400) { - results = JSON.parse(results); + results = json.parse(results); status = results['status']; } if (results is Map && (results as Map).containsKey('value')) { diff --git a/runtime/bin/builtin.h b/runtime/bin/builtin.h index b21c9af475f..ca33e572ce0 100644 --- a/runtime/bin/builtin.h +++ b/runtime/bin/builtin.h @@ -45,6 +45,7 @@ class Builtin { static Dart_NativeFunction BuiltinNativeLookup(Dart_Handle name, int argument_count); + static const char async_source_[]; static const char builtin_source_[]; static const char crypto_source_[]; static const char io_source_[]; diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc index 6257db653b0..c813d90c125 100644 --- a/runtime/bin/dartutils.cc +++ b/runtime/bin/dartutils.cc @@ -15,6 +15,7 @@ const char* DartUtils::original_working_directory = NULL; const char* DartUtils::kDartScheme = "dart:"; const char* DartUtils::kDartExtensionScheme = "dart-ext:"; +const char* DartUtils::kASyncLibURL = "dart:async"; const char* DartUtils::kBuiltinLibURL = "dart:builtin"; const char* DartUtils::kCoreLibURL = "dart:core"; const char* DartUtils::kCryptoLibURL = "dart:crypto"; @@ -416,17 +417,17 @@ Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root, print); // Setup the 'timer' factory. - Dart_Handle url = NewString(kIsolateLibURL); + Dart_Handle url = NewString(kASyncLibURL); DART_CHECK_VALID(url); - Dart_Handle isolate_lib = Dart_LookupLibrary(url); - DART_CHECK_VALID(isolate_lib); + Dart_Handle async_lib = Dart_LookupLibrary(url); + DART_CHECK_VALID(async_lib); Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary); Dart_Handle timer_closure = Dart_Invoke(io_lib, NewString("_getTimerFactoryClosure"), 0, NULL); Dart_Handle args[1]; args[0] = timer_closure; DART_CHECK_VALID(Dart_Invoke( - isolate_lib, NewString("_setTimerFactoryClosure"), 1, args)); + async_lib, NewString("_setTimerFactoryClosure"), 1, args)); // Set up package root if specified. if (package_root != NULL) { diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h index e027d8ae89d..ce9f3f41d4a 100644 --- a/runtime/bin/dartutils.h +++ b/runtime/bin/dartutils.h @@ -162,6 +162,7 @@ class DartUtils { static const char* kDartScheme; static const char* kDartExtensionScheme; + static const char* kASyncLibURL; static const char* kBuiltinLibURL; static const char* kCoreLibURL; static const char* kCryptoLibURL; diff --git a/runtime/bin/io.dart b/runtime/bin/io.dart index cd39eeeb538..8feca0eab30 100644 --- a/runtime/bin/io.dart +++ b/runtime/bin/io.dart @@ -7,6 +7,7 @@ // file which is in lib/io/io.dart. #library("dart:io"); +#import("dart:async"); #import("dart:crypto"); #import("dart:isolate"); #import("dart:math"); diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart index 34ca47685a2..fc5f72b3d0c 100644 --- a/runtime/bin/process_patch.dart +++ b/runtime/bin/process_patch.dart @@ -53,7 +53,7 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { throw new ArgumentError("Arguments is not a List: $arguments"); } int len = arguments.length; - _arguments = new List(len); + _arguments = new List.fixedLength(len); for (int i = 0; i < len; i++) { var arg = arguments[i]; if (arg is !String) { @@ -170,7 +170,7 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { _out.close(); _err.close(); _exitHandler.close(); - completer.completeException( + completer.completeError( new ProcessException(_path, _arguments, status._errorMessage, @@ -194,7 +194,7 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { // callback when a process terminates. int exitDataRead = 0; final int EXIT_DATA_SIZE = 8; - List exitDataBuffer = new List(EXIT_DATA_SIZE); + List exitDataBuffer = new List.fixedLength(EXIT_DATA_SIZE); _exitHandler.inputStream.onData = () { int exitCode(List ints) { @@ -206,9 +206,8 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { void handleExit() { _ended = true; - if (_onExit != null) { - _onExit(exitCode(exitDataBuffer)); - } + _exitCode = exitCode(exitDataBuffer); + if (_onExit != null) _onExit(_exitCode); _out.close(); } @@ -257,12 +256,28 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { return _kill(this, signal._signalNumber); } + void add(List data) { + stdin.write(data); + } + + void close() { + stdin.close(); + } + + void signalError(ASyncError error) { + // TODO(ajohnsen): close? + } + + Stream> get stdoutStream + => new _InputStreamController(stdout).stream; + + Stream> get stderrStream + => new _InputStreamController(stderr).stream; + bool _kill(Process p, int signal) native "Process_Kill"; void set onExit(void callback(int exitCode)) { - if (_ended) { - throw new ProcessException(_path, _arguments, "Process killed"); - } + if (_ended) callback(_exitCode); _onExit = callback; } @@ -275,6 +290,7 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { _Socket _out; _Socket _err; Socket _exitHandler; + int _exitCode; bool _ended; bool _started; Function _onExit; @@ -346,11 +362,8 @@ class _NonInteractiveProcess { _stderrClosed = true; _checkDone(); }; - }); - - processFuture.handleException((error) { - _completer.completeException(error); - return true; + }).catchError((error) { + _completer.completeError(error.error); }); } diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart index 3b502a2f32a..bc91a3272cf 100644 --- a/runtime/bin/socket_patch.dart +++ b/runtime/bin/socket_patch.dart @@ -45,7 +45,7 @@ class _SocketBase extends NativeFieldWrapperClass1 { static const int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND; _SocketBase () { - _handlerMap = new List(_LAST_EVENT + 1); + _handlerMap = new List.fixedLength(_LAST_EVENT + 1); _handlerMask = 0; _canActivateHandlers = true; _closed = true; @@ -339,7 +339,7 @@ class _Socket extends _SocketBase implements Socket { factory _Socket(String host, int port) { Socket socket = new _Socket._internal(); _ensureSocketService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = HOST_NAME_LOOKUP; request[1] = host; _socketService.call(request).then((response) { diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart index 1748654b13a..f5e8ec33ffe 100644 --- a/runtime/lib/array.dart +++ b/runtime/lib/array.dart @@ -61,31 +61,68 @@ class _ObjectArray implements List { // Collection interface. - bool contains(E element) => Collections.contains(this, element); + bool contains(E element) { + return Collections.contains(this, element); + } void forEach(f(E element)) { Collections.forEach(this, f); } - Collection map(f(E element)) { - return Collections.map( - this, new _GrowableObjectArray.withCapacity(length), f); + String join([String separator]) { + return Collections.join(this, separator); + } + + List mappedBy(f(E element)) { + return new MappedList(this, f); } reduce(initialValue, combine(previousValue, E element)) { return Collections.reduce(this, initialValue, combine); } - Collection filter(bool f(E element)) { - return Collections.filter(this, new _GrowableObjectArray(), f); + Iterable where(bool f(E element)) { + return new WhereIterable(this, f); + } + + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(E value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(E value)) { + return new SkipWhileIterable(this, test); } bool every(bool f(E element)) { return Collections.every(this, f); } - bool some(bool f(E element)) { - return Collections.some(this, f); + bool any(bool f(E element)) { + return Collections.any(this, f); + } + + E firstMatching(bool test(E value), {E orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + E lastMatching(bool test(E value), {E orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + E singleMatching(bool test(E value)) { + return Collections.singleMatching(this, test); + } + + E elementAt(int index) { + return this[index]; } bool get isEmpty { @@ -106,7 +143,7 @@ class _ObjectArray implements List { return Arrays.lastIndexOf(this, element, start); } - Iterator iterator() { + Iterator get iterator { return new _FixedSizeArrayIterator(this); } @@ -119,7 +156,7 @@ class _ObjectArray implements List { add(element); } - void addAll(Collection elements) { + void addAll(Iterable iterable) { throw new UnsupportedError( "Cannot add to a non-extendable array"); } @@ -140,11 +177,31 @@ class _ObjectArray implements List { } E get first { - return this[0]; + if (length > 0) return this[0]; + throw new StateError("No elements"); } E get last { - return this[length - 1]; + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); + } + + E get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + E min([int compare(E a, E b)]) => Collections.min(this, compare); + + E max([int compare(E a, E b)]) => Collections.max(this, compare); + + List toList() { + return new List.from(this); + } + + Set toSet() { + return new Set.from(this); } } @@ -208,31 +265,68 @@ class _ImmutableArray implements List { // Collection interface. - bool contains(E element) => Collections.contains(this, element); + bool contains(E element) { + return Collections.contains(this, element); + } void forEach(f(E element)) { Collections.forEach(this, f); } - Collection map(f(E element)) { - return Collections.map( - this, new _GrowableObjectArray.withCapacity(length), f); + List mappedBy(f(E element)) { + return new MappedList(this, f); + } + + String join([String separator]) { + return Collections.join(this, separator); } reduce(initialValue, combine(previousValue, E element)) { return Collections.reduce(this, initialValue, combine); } - Collection filter(bool f(E element)) { - return Collections.filter(this, new _GrowableObjectArray(), f); + Iterable where(bool f(E element)) { + return new WhereIterable(this, f); + } + + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(E value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(E value)) { + return new SkipWhileIterable(this, test); } bool every(bool f(E element)) { return Collections.every(this, f); } - bool some(bool f(E element)) { - return Collections.some(this, f); + bool any(bool f(E element)) { + return Collections.any(this, f); + } + + E firstMatching(bool test(E value), {E orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + E lastMatching(bool test(E value), {E orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + E singleMatching(bool test(E value)) { + return Collections.singleMatching(this, test); + } + + E elementAt(int index) { + return this[index]; } bool get isEmpty { @@ -257,7 +351,7 @@ class _ImmutableArray implements List { return Arrays.lastIndexOf(this, element, start); } - Iterator iterator() { + Iterator get iterator { return new _FixedSizeArrayIterator(this); } @@ -270,7 +364,7 @@ class _ImmutableArray implements List { add(element); } - void addAll(Collection elements) { + void addAll(Iterable elements) { throw new UnsupportedError( "Cannot add to an immutable array"); } @@ -291,34 +385,60 @@ class _ImmutableArray implements List { } E get first { - return this[0]; + if (length > 0) return this[0]; + throw new StateError("No elements"); } E get last { - return this[length - 1]; + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); + } + + E get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + E min([int compare(E a, E b)]) => Collections.min(this, compare); + + E max([int compare(E a, E b)]) => Collections.max(this, compare); + + List toList() { + return new List.from(this); + } + + Set toSet() { + return new Set.from(this); } } // Iterator for arrays with fixed size. class _FixedSizeArrayIterator implements Iterator { + final List _array; + final int _length; // Cache array length for faster access. + int _position; + E _current; + _FixedSizeArrayIterator(List array) - : _array = array, _length = array.length, _pos = 0 { + : _array = array, _length = array.length, _position = -1 { assert(array is _ObjectArray || array is _ImmutableArray); } - bool get hasNext { - return _length > _pos; - } - - E next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; } - return _array[_pos++]; + _position = _length; + _current = null; + return false; } - final List _array; - final int _length; // Cache array length for faster access. - int _pos; + E get current { + return _current; + } } diff --git a/runtime/lib/array_patch.dart b/runtime/lib/array_patch.dart index 2887a994d7a..bdcf29ccbcf 100644 --- a/runtime/lib/array_patch.dart +++ b/runtime/lib/array_patch.dart @@ -6,12 +6,43 @@ // returns a _GrowableObjectArray if length is null, otherwise returns // fixed size array. patch class List { - /* patch */ factory List([int length = null]) { - if (length == null) { - return new _GrowableObjectArray(); - } else { - return new _ObjectArray(length); + /* patch */ factory List([int length = 0]) { + if (length is! int || length < 0) { + throw new ArgumentError("Length must be a positive integer: $length."); } + _GrowableObjectArray result = new _GrowableObjectArray(); + result.length = length; + return result; + } + + /* patch */ factory List.fixedLength(int length, {E fill: null}) { + if (length is! int || length < 0) { + throw new ArgumentError("Length must be a positive integer: $length."); + } + _ObjectArray result = new _ObjectArray(length); + if (fill != null) { + for (int i = 0; i < length; i++) { + result[i] = fill; + } + } + return result; + } + + /* patch */ factory List.filled(int length, E fill) { + if (length is! int || length < 0) { + throw new ArgumentError("Length must be a positive integer: $length."); + } + _GrowableObjectArray result = + new _GrowableObjectArray.withCapacity(length < 4 ? 4 : length); + if (length != 0) { + result.length = length; + if (fill != null) { + for (int i = 0; i < length; i++) { + result[i] = fill; + } + } + } + return result; } // Factory constructing a mutable List from a parser generated List literal. diff --git a/runtime/lib/async_sources.gypi b/runtime/lib/async_sources.gypi new file mode 100644 index 00000000000..d1c0711679a --- /dev/null +++ b/runtime/lib/async_sources.gypi @@ -0,0 +1,10 @@ +# Copyright (c) 2012, 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. + +# This file contains all sources for the dart:isolate library. +{ + 'sources': [ + 'timer_patch.dart', + ], +} diff --git a/runtime/lib/byte_array.dart b/runtime/lib/byte_array.dart index 61be89d704c..f1358ce5f06 100644 --- a/runtime/lib/byte_array.dart +++ b/runtime/lib/byte_array.dart @@ -196,8 +196,12 @@ abstract class _ByteArrayBase { } } - Collection map(f(element)) { - return Collections.map(this, new List(), f); + List mappedBy(f(int element)) { + return new MappedList(this, f); + } + + String join([String separator]) { + return Collections.join(this, separator); } dynamic reduce(dynamic initialValue, @@ -205,16 +209,48 @@ abstract class _ByteArrayBase { return Collections.reduce(this, initialValue, combine); } - Collection filter(bool f(element)) { - return Collections.filter(this, new List(), f); + Collection where(bool f(element)) { + return new WhereIterable(this, f); + } + + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); } bool every(bool f(element)) { return Collections.every(this, f); } - bool some(bool f(element)) { - return Collections.some(this, f); + bool any(bool f(element)) { + return Collections.any(this, f); + } + + int firstMatching(bool test(int value), {int orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; } bool get isEmpty { @@ -242,7 +278,7 @@ abstract class _ByteArrayBase { "Cannot add to a non-extendable array"); } - void addAll(Collection value) { + void addAll(Iterable value) { throw new UnsupportedError( "Cannot add to a non-extendable array"); } @@ -271,14 +307,26 @@ abstract class _ByteArrayBase { "Cannot remove from a non-extendable array"); } - get first { - return this[0]; + int get first { + if (length > 0) return this[0]; + throw new StateError("No elements"); } - get last { - return this[length - 1]; + int get last { + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); } + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => Collections.min(this, compare); + + int max([int compare(int a, int b)]) => Collections.max(this, compare); + void removeRange(int start, int length) { throw new UnsupportedError( "Cannot remove from a non-extendable array"); @@ -299,6 +347,14 @@ abstract class _ByteArrayBase { length * this.bytesPerElement()); } + List toList() { + return new List.from(this); + } + + Set toSet() { + return new Set.from(this); + } + int _length() native "ByteArray_getLength"; void _setRange(int startInBytes, int lengthInBytes, @@ -436,7 +492,7 @@ class _Int8Array extends _ByteArrayBase implements Int8List { _setIndexed(index, _toInt8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -505,7 +561,7 @@ class _Uint8Array extends _ByteArrayBase implements Uint8List { _setIndexed(index, _toUint8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -576,7 +632,7 @@ class _Uint8ClampedArray extends _ByteArrayBase implements Uint8ClampedList { _setIndexed(index, _toClampedUint8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -646,7 +702,7 @@ class _Int16Array extends _ByteArrayBase implements Int16List { _setIndexed(index, _toInt16(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -715,7 +771,7 @@ class _Uint16Array extends _ByteArrayBase implements Uint16List { _setIndexed(index, _toUint16(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -784,7 +840,7 @@ class _Int32Array extends _ByteArrayBase implements Int32List { _setIndexed(index, _toInt32(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -854,7 +910,7 @@ class _Uint32Array extends _ByteArrayBase implements Uint32List { _setIndexed(index, _toUint32(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -923,7 +979,7 @@ class _Int64Array extends _ByteArrayBase implements Int64List { _setIndexed(index, _toInt64(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -992,7 +1048,7 @@ class _Uint64Array extends _ByteArrayBase implements Uint64List { _setIndexed(index, _toUint64(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1061,7 +1117,7 @@ class _Float32Array extends _ByteArrayBase implements Float32List { _setIndexed(index, value); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1130,7 +1186,7 @@ class _Float64Array extends _ByteArrayBase implements Float64List { _setIndexed(index, value); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1184,7 +1240,7 @@ class _ExternalInt8Array extends _ByteArrayBase implements Int8List { _setIndexed(index, _toInt8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1234,7 +1290,7 @@ class _ExternalUint8Array extends _ByteArrayBase implements Uint8List { _setIndexed(index, _toUint8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1284,7 +1340,7 @@ class _ExternalInt16Array extends _ByteArrayBase implements Int16List { _setIndexed(index, _toInt16(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1334,7 +1390,7 @@ class _ExternalUint16Array extends _ByteArrayBase implements Uint16List { _setIndexed(index, _toUint16(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1386,7 +1442,7 @@ class _ExternalInt32Array extends _ByteArrayBase implements Int32List { _setIndexed(index, _toInt32(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1438,7 +1494,7 @@ class _ExternalUint32Array extends _ByteArrayBase implements Uint32List { _setIndexed(index, _toUint32(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1490,7 +1546,7 @@ class _ExternalInt64Array extends _ByteArrayBase implements Int64List { _setIndexed(index, _toInt64(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1542,7 +1598,7 @@ class _ExternalUint64Array extends _ByteArrayBase implements Uint64List { _setIndexed(index, _toUint64(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1594,7 +1650,7 @@ class _ExternalFloat32Array extends _ByteArrayBase implements Float32List { _setIndexed(index, value); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1646,7 +1702,7 @@ class _ExternalFloat64Array extends _ByteArrayBase implements Float64List { _setIndexed(index, value); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -1690,25 +1746,29 @@ class _ExternalFloat64Array extends _ByteArrayBase implements Float64List { class _ByteArrayIterator implements Iterator { + final List _array; + final int _length; + int _position; + E _current; + _ByteArrayIterator(List array) - : _array = array, _length = array.length, _pos = 0 { + : _array = array, _length = array.length, _position = -1 { assert(array is _ByteArrayBase || array is _ByteArrayViewBase); } - bool get hasNext { - return _length > _pos; - } - - E next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; } - return _array[_pos++]; + _position = _length; + _current = null; + return false; } - final List _array; - final int _length; - int _pos; + E get current => _current; } @@ -1807,7 +1867,10 @@ class _ByteArrayView implements ByteArray { } -class _ByteArrayViewBase { +// TODO(floitsch): extending the collection adds extra cost (because of type +// parameters). Consider copying the functions from Collection into this class +// and just implementing Collection. +class _ByteArrayViewBase extends Collection { num operator[](int index); // Methods implementing the Collection interface. @@ -1819,27 +1882,6 @@ class _ByteArrayViewBase { } } - Collection map(f(element)) { - return Collections.map(this, new List(), f); - } - - dynamic reduce(dynamic initialValue, - dynamic combine(dynamic initialValue, element)) { - return Collections.reduce(this, initialValue, combine); - } - - Collection filter(bool f(element)) { - return Collections.filter(this, new List(), f); - } - - bool every(bool f(element)) { - return Collections.every(this, f); - } - - bool some(bool f(element)) { - return Collections.some(this, f);; - } - bool get isEmpty { return this.length == 0; } @@ -1863,7 +1905,7 @@ class _ByteArrayViewBase { "Cannot add to a non-extendable array"); } - void addAll(Collection value) { + void addAll(Iterable value) { throw new UnsupportedError( "Cannot add to a non-extendable array"); } @@ -1892,12 +1934,20 @@ class _ByteArrayViewBase { "Cannot remove from a non-extendable array"); } - get first { - return this[0]; + int get first { + if (length > 0) return this[0]; + throw new StateError("No elements"); } - get last { - return this[length - 1]; + int get last { + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); } void removeRange(int start, int length) { @@ -1942,7 +1992,7 @@ class _Int8ArrayView extends _ByteArrayViewBase implements Int8List { _array.setInt8(_offset + (index * _BYTES_PER_ELEMENT), _toInt8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2014,7 +2064,7 @@ class _Uint8ArrayView extends _ByteArrayViewBase implements Uint8List { _array.setUint8(_offset + (index * _BYTES_PER_ELEMENT), _toUint8(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2086,7 +2136,7 @@ class _Int16ArrayView extends _ByteArrayViewBase implements Int16List { _array.setInt16(_offset + (index * _BYTES_PER_ELEMENT), _toInt16(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2158,7 +2208,7 @@ class _Uint16ArrayView extends _ByteArrayViewBase implements Uint16List { _array.setUint16(_offset + (index * _BYTES_PER_ELEMENT), _toUint16(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2230,7 +2280,7 @@ class _Int32ArrayView extends _ByteArrayViewBase implements Int32List { _array.setInt32(_offset + (index * _BYTES_PER_ELEMENT), _toInt32(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2302,7 +2352,7 @@ class _Uint32ArrayView extends _ByteArrayViewBase implements Uint32List { _array.setUint32(_offset + (index * _BYTES_PER_ELEMENT), _toUint32(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2374,7 +2424,7 @@ class _Int64ArrayView extends _ByteArrayViewBase implements Int64List { _array.setInt64(_offset + (index * _BYTES_PER_ELEMENT), _toInt64(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2446,7 +2496,7 @@ class _Uint64ArrayView extends _ByteArrayViewBase implements Uint64List { _array.setUint64(_offset + (index * _BYTES_PER_ELEMENT), _toUint64(value)); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2518,7 +2568,7 @@ class _Float32ArrayView extends _ByteArrayViewBase implements Float32List { _array.setFloat32(_offset + (index * _BYTES_PER_ELEMENT), value); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } @@ -2590,7 +2640,7 @@ class _Float64ArrayView extends _ByteArrayViewBase implements Float64List { _array.setFloat64(_offset + (index * _BYTES_PER_ELEMENT), value); } - Iterator iterator() { + Iterator get iterator { return new _ByteArrayIterator(this); } diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc index 7a15d5b28ac..b2c11f72783 100644 --- a/runtime/lib/double.cc +++ b/runtime/lib/double.cc @@ -79,7 +79,20 @@ DEFINE_NATIVE_ENTRY(Double_trunc_div, 2) { if (FLAG_trace_intrinsified_natives) { OS::Print("Double_trunc_div %f ~/ %f\n", left, right); } - return Double::New(trunc(left / right)); + double result = trunc(left / right); + if (isinf(result) || isnan(result)) { + const Array& args = Array::Handle(Array::New(1)); + args.SetAt(0, String::Handle(String::New( + "Result of truncating division is Infinity or NaN"))); + Exceptions::ThrowByType(Exceptions::kUnsupported, args); + } + if ((Smi::kMinValue <= result) && (result <= Smi::kMaxValue)) { + return Smi::New(static_cast(result)); + } else if ((Mint::kMinValue <= result) && (result <= Mint::kMaxValue)) { + return Mint::New(static_cast(result)); + } else { + return BigintOperations::NewFromDouble(result); + } } @@ -191,7 +204,7 @@ DEFINE_NATIVE_ENTRY(Double_toInt, 1) { if (isinf(arg.value()) || isnan(arg.value())) { const Array& args = Array::Handle(Array::New(1)); args.SetAt(0, String::Handle(String::New("Infinity or NaN toInt"))); - Exceptions::ThrowByType(Exceptions::kFormat, args); + Exceptions::ThrowByType(Exceptions::kUnsupported, args); } double result = trunc(arg.value()); if ((Smi::kMinValue <= result) && (result <= Smi::kMaxValue)) { diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart index aee84e23bc7..decfb570389 100644 --- a/runtime/lib/double.dart +++ b/runtime/lib/double.dart @@ -6,11 +6,8 @@ class _Double implements double { factory _Double.fromInteger(int value) native "Double_doubleFromInteger"; int get hashCode { - try { - return toInt(); - } on FormatException catch (e) { - return 0; - } + if (isNaN || isInfinite) return 0; + return toInt(); } double operator +(num other) { return _add(other.toDouble()); @@ -27,10 +24,10 @@ class _Double implements double { } double _mul(double other) native "Double_mul"; - double operator ~/(num other) { + int operator ~/(num other) { return _trunc_div(other.toDouble()); } - double _trunc_div(double other) native "Double_trunc_div"; + int _trunc_div(double other) native "Double_trunc_div"; double operator /(num other) { return _div(other.toDouble()); @@ -81,7 +78,7 @@ class _Double implements double { double _mulFromInteger(int other) { return new _Double.fromInteger(other) * this; } - double _truncDivFromInteger(int other) { + int _truncDivFromInteger(int other) { return new _Double.fromInteger(other) ~/ this; } double _moduloFromInteger(int other) { @@ -107,6 +104,20 @@ class _Double implements double { double floor() native "Double_floor"; double ceil () native "Double_ceil"; double truncate() native "Double_truncate"; + + num clamp(num lowerLimit, num upperLimit) { + if (lowerLimit is! num) throw new ArgumentError(lowerLimit); + if (upperLimit is! num) throw new ArgumentError(upperLimit); + + if (lowerLimit.compareTo(upperLimit) > 0) { + throw new ArgumentError(lowerLimit); + } + if (lowerLimit.isNaN) return lowerLimit; + if (this.compareTo(lowerLimit) < 0) return lowerLimit; + if (this.compareTo(upperLimit) > 0) return upperLimit; + return this; + } + int toInt() native "Double_toInt"; double toDouble() { return this; } @@ -128,10 +139,12 @@ class _Double implements double { String toStringAsFixed(int fractionDigits) { // See ECMAScript-262, 15.7.4.5 for details. + if (fractionDigits is! int) { + throw new ArgumentError(fractionDigits); + } // Step 2. if (fractionDigits < 0 || fractionDigits > 20) { - // TODO(antonm): should be proper RangeError or Dart counterpart. - throw "Range error"; + throw new RangeError(fractionDigits); } // Step 3. @@ -151,7 +164,7 @@ class _Double implements double { } String _toStringAsFixed(int fractionDigits) native "Double_toStringAsFixed"; - String toStringAsExponential(int fractionDigits) { + String toStringAsExponential([int fractionDigits]) { // See ECMAScript-262, 15.7.4.6 for details. // The EcmaScript specification checks for NaN and Infinity before looking @@ -159,10 +172,13 @@ class _Double implements double { // look at the fractionDigits first. // Step 7. - if (fractionDigits != null && - (fractionDigits < 0 || fractionDigits > 20)) { - // TODO(antonm): should be proper RangeError or Dart counterpart. - throw "Range error"; + if (fractionDigits != null) { + if (fractionDigits is! int) { + throw new ArgumentError(fractionDigits); + } + if (fractionDigits < 0 || fractionDigits > 20) { + throw new RangeError(fractionDigits); + } } if (isNaN) return "NaN"; @@ -185,10 +201,11 @@ class _Double implements double { // at the fractionDigits. In Dart we are consistent with toStringAsFixed and // look at the fractionDigits first. + if (precision is! int) throw new ArgumentError(precision); + // Step 8. if (precision < 1 || precision > 21) { - // TODO(antonm): should be proper RangeError or Dart counterpart. - throw "Range error"; + throw new RangeError(precision); } if (isNaN) return "NaN"; @@ -200,10 +217,6 @@ class _Double implements double { String _toStringAsPrecision(int fractionDigits) native "Double_toStringAsPrecision"; - String toRadixString(int radix) { - return toInt().toRadixString(radix); - } - // Order is: NaN > Infinity > ... > 0.0 > -0.0 > ... > -Infinity. int compareTo(Comparable other) { final int EQUAL = 0, LESS = -1, GREATER = 1; diff --git a/runtime/lib/double_patch.dart b/runtime/lib/double_patch.dart index 5e6cc110da2..e56f45dc74c 100644 --- a/runtime/lib/double_patch.dart +++ b/runtime/lib/double_patch.dart @@ -6,6 +6,15 @@ // VM implementation of double. patch class double { - /* patch */ - static double parse(String string) native "Double_parse"; + static double _parse(String string) native "Double_parse"; + + /* patch */ static double parse(String str, + [double handleError(String str)]) { + if (handleError == null) return _parse(str); + try { + return _parse(str); + } on FormatException { + return handleError(str); + } + } } diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart index 1cfeaafc97b..75369a260ab 100644 --- a/runtime/lib/expando_patch.dart +++ b/runtime/lib/expando_patch.dart @@ -21,7 +21,7 @@ patch class Expando { } } if (doCompact) { - _data = _data.filter((e) => (e != null)); + _data = _data.where((e) => (e != null)).toList(); } return result; } @@ -49,7 +49,7 @@ patch class Expando { _data.add(new _WeakProperty(object, value)); } if (doCompact) { - _data = _data.filter((e) => (e != null)); + _data = _data.where((e) => (e != null)).toList(); } } diff --git a/runtime/lib/function_patch.dart b/runtime/lib/function_patch.dart index 56b817dada6..cb5a0c27411 100644 --- a/runtime/lib/function_patch.dart +++ b/runtime/lib/function_patch.dart @@ -13,10 +13,10 @@ patch class Function { (positionalArguments != null ? positionalArguments.length : 0); int numNamedArguments = namedArguments != null ? namedArguments.length : 0; int numArguments = numPositionalArguments + numNamedArguments; - List arguments = new List(numArguments); + List arguments = new List.fixedLength(numArguments); arguments[0] = function; arguments.setRange(1, numPositionalArguments - 1, positionalArguments); - List names = new List(numNamedArguments); + List names = new List.fixedLength(numNamedArguments); int argumentIndex = numPositionalArguments; int nameIndex = 0; if (numNamedArguments > 0) { diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart index 9caad29d211..9f9fc82ea55 100644 --- a/runtime/lib/growable_array.dart +++ b/runtime/lib/growable_array.dart @@ -131,8 +131,8 @@ class _GrowableObjectArray implements List { add(element); } - void addAll(Collection collection) { - for (T elem in collection) { + void addAll(Iterable iterable) { + for (T elem in iterable) { add(elem); } } @@ -146,13 +146,25 @@ class _GrowableObjectArray implements List { } T get first { - return this[0]; + if (length > 0) return this[0]; + throw new StateError("No elements"); } T get last { - return this[length - 1]; + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); } + T get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + T min([int compare(T a, T b)]) => Collections.min(this, compare); + + T max([int compare(T a, T b)]) => Collections.max(this, compare); + int indexOf(T element, [int start = 0]) { return Arrays.indexOf(this, element, start, length); } @@ -172,7 +184,9 @@ class _GrowableObjectArray implements List { // Collection interface. - bool contains(T element) => Collections.contains(this, element); + bool contains(T element) { + return Collections.contains(this, element); + } void forEach(f(T element)) { // TODO(srdjan): Use Collections.forEach(this, f); @@ -182,25 +196,74 @@ class _GrowableObjectArray implements List { } } - Collection map(f(T element)) { - return Collections.map(this, - new _GrowableObjectArray.withCapacity(length), f); + String join([String separator]) { + if (isEmpty) return ""; + if (this.length == 1) return "${this[0]}"; + StringBuffer buffer = new StringBuffer(); + if (separator == null || separator == "") { + for (int i = 0; i < this.length; i++) { + buffer.add("${this[i]}"); + } + } else { + buffer.add("${this[0]}"); + for (int i = 1; i < this.length; i++) { + buffer.add(separator); + buffer.add("${this[i]}"); + } + } + return buffer.toString(); + } + + List mappedBy(f(T element)) { + return new MappedList(this, f); } reduce(initialValue, combine(previousValue, T element)) { return Collections.reduce(this, initialValue, combine); } - Collection filter(bool f(T element)) { - return Collections.filter(this, new _GrowableObjectArray(), f); + Iterable where(bool f(T element)) { + return new WhereIterable(this, f); + } + + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(T value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(T value)) { + return new SkipWhileIterable(this, test); } bool every(bool f(T element)) { return Collections.every(this, f); } - bool some(bool f(T element)) { - return Collections.some(this, f); + bool any(bool f(T element)) { + return Collections.any(this, f); + } + + T firstMatching(bool test(T value), {T orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + T lastMatching(bool test(T value), {T orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + T singleMatching(bool test(T value)) { + return Collections.singleMatching(this, test); + } + + T elementAt(int index) { + return this[index]; } bool get isEmpty { @@ -220,7 +283,15 @@ class _GrowableObjectArray implements List { return Collections.collectionToString(this); } - Iterator iterator() { - return new SequenceIterator(this); + Iterator get iterator { + return new ListIterator(this); + } + + List toList() { + return new List.from(this); + } + + Set toSet() { + return new Set.from(this); } } diff --git a/runtime/lib/immutable_map.dart b/runtime/lib/immutable_map.dart index aa33a6dcbbc..82f54580e44 100644 --- a/runtime/lib/immutable_map.dart +++ b/runtime/lib/immutable_map.dart @@ -35,22 +35,12 @@ class ImmutableMap implements Map { } } - Collection get keys { - int numKeys = length; - List list = new List(numKeys); - for (int i = 0; i < numKeys; i++) { - list[i] = kvPairs_[i*2]; - } - return list; + Iterable get keys { + return new _ImmutableMapKeyIterable(this); } - Collection get values { - int numValues = length; - List list = new List(numValues); - for (int i = 0; i < numValues; i++) { - list[i] = kvPairs_[i*2 + 1]; - } - return list; + Iterable get values { + return new _ImmutableMapValueIterable(this); } bool containsKey(K key) { @@ -92,3 +82,64 @@ class ImmutableMap implements Map { } } +class _ImmutableMapKeyIterable extends Iterable { + final ImmutableMap _map; + _ImmutableMapKeyIterable(this._map); + + Iterator get iterator { + return new _ImmutableMapKeyIterator(_map); + } +} + +class _ImmutableMapValueIterable extends Iterable { + final ImmutableMap _map; + _ImmutableMapValueIterable(this._map); + + Iterator get iterator { + return new _ImmutableMapValueIterator(_map); + } +} + +class _ImmutableMapKeyIterator implements Iterator { + ImmutableMap _map; + int _index = -1; + E _current; + + _ImmutableMapKeyIterator(this._map); + + bool moveNext() { + int newIndex = _index + 1; + if (newIndex < _map.length) { + _index = newIndex; + _current = _map.kvPairs_[newIndex * 2]; + return true; + } + _current = null; + _index = _map.length; + return false; + } + + E get current => _current; +} + +class _ImmutableMapValueIterator implements Iterator { + ImmutableMap _map; + int _index = -1; + E _current; + + _ImmutableMapValueIterator(this._map); + + bool moveNext() { + int newIndex = _index + 1; + if (newIndex < _map.length) { + _index = newIndex; + _current = _map.kvPairs_[newIndex * 2 + 1]; + return true; + } + _current = null; + _index = _map.length; + return false; + } + + E get current => _current; +} diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart index cdf43b3fe73..2b3a1ee768f 100644 --- a/runtime/lib/integers.dart +++ b/runtime/lib/integers.dart @@ -131,6 +131,30 @@ class _IntegerImplementation { int ceil() { return this; } int truncate() { return this; } + num clamp(num lowerLimit, num upperLimit) { + if (lowerLimit is! num) throw new ArgumentError(lowerLimit); + if (upperLimit is! num) throw new ArgumentError(upperLimit); + + // Special case for integers. + if (lowerLimit is int && upperLimit is int) { + if (lowerLimit > upperLimit) { + throw new ArgumentError(lowerLimit); + } + if (this < lowerLimit) return lowerLimit; + if (this > upperLimit) return upperLimit; + return this; + } + // Generic case involving doubles. + if (lowerLimit.compareTo(upperLimit) > 0) { + throw new ArgumentError(lowerLimit); + } + if (lowerLimit.isNaN) return lowerLimit; + // Note that we don't need to care for -0.0 for the lower limit. + if (this < lowerLimit) return lowerLimit; + if (this.compareTo(upperLimit) > 0) return upperLimit; + return this; + } + int toInt() { return this; } double toDouble() { return new _Double.fromInteger(this); } @@ -146,25 +170,26 @@ class _IntegerImplementation { String toStringAsFixed(int fractionDigits) { return this.toDouble().toStringAsFixed(fractionDigits); } - String toStringAsExponential(int fractionDigits) { + String toStringAsExponential([int fractionDigits]) { return this.toDouble().toStringAsExponential(fractionDigits); } String toStringAsPrecision(int precision) { return this.toDouble().toStringAsPrecision(precision); } + String toRadixString(int radix) { final table = const ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]; - if (radix < 2 || radix > 36) { + if (radix is! int || radix < 2 || radix > 36) { throw new ArgumentError(radix); } final bool isNegative = this < 0; - var value = isNegative ? -this : this; + int value = isNegative ? -this : this; List temp = new List(); while (value > 0) { - var digit = value % radix; + int digit = value % radix; value ~/= radix; temp.add(digit); } diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart index 162c05004df..530ac1dbb01 100644 --- a/runtime/lib/integers_patch.dart +++ b/runtime/lib/integers_patch.dart @@ -6,5 +6,66 @@ // VM implementation of int. patch class int { - /* patch */ static int parse(String str) native "Integer_parse"; + static int _parse(String str) native "Integer_parse"; + + static void _throwFormatException(String source) { + throw new FormatException(source); + } + + /* patch */ static int parse(String source, + { int radix, + int onError(String str) }) { + if (source is! String) throw new ArgumentError(source); + if (radix == null) { + if (onError == null) return _parse(source); + try { + return _parse(source); + } on FormatException { + return onError(source); + } + } + if (radix is! int) throw new ArgumentError("Radix is not an integer"); + if (radix < 2 || radix > 36) { + throw new RangeError("Radix $radix not in range 2..36"); + } + if (onError == null) { + onError = _throwFormatException; + } + // Remove leading and trailing white space. + source = source.trim(); + if (source.isEmpty) return onError(source); + + bool negative = false; + int result = 0; + + // The value 99 is used to represent a non-digit. It is too large to be + // a digit value in any of the used bases. + const NA = 99; + const List digits = const [ + 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, NA, NA, NA, NA, NA, NA, // 0x30 + NA, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40 + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NA, NA, NA, NA, NA, // 0x50 + NA, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x60 + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NA, NA, NA, NA, NA, // 0x70 + ]; + + int i = 0; + int code = source.charCodeAt(i); + if (code == 0x2d || code == 0x2b) { // Starts with a plus or minus-sign. + negative = (code == 0x2d); + if (source.length == 1) return onError(source); + i = 1; + code = source.charCodeAt(i); + } + do { + if (code < 0x30 || code > 0x7f) return onError(source); + int digit = digits[code - 0x30]; + if (digit >= radix) return onError(source); + result = result * radix + digit; + i++; + if (i == source.length) break; + code = source.charCodeAt(i); + } while (true); + return negative ? -result : result; + } } diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart index 03ec6648a3b..a521a636efe 100644 --- a/runtime/lib/isolate_patch.dart +++ b/runtime/lib/isolate_patch.dart @@ -85,7 +85,7 @@ class _SendPortImpl implements SendPort { port.receive((value, ignoreReplyTo) { port.close(); if (value is Exception) { - completer.completeException(value); + completer.completeError(value); } else { completer.complete(value); } @@ -122,50 +122,17 @@ _getPortInternal() native "isolate_getPortInternal"; ReceivePort _portInternal; -patch ReceivePort get port { - if (_portInternal == null) { - _portInternal = _getPortInternal(); - } - return _portInternal; -} - -patch spawnFunction(void topLevelFunction(), - [bool UnhandledExceptionCallback(IsolateUnhandledException e)]) - native "isolate_spawnFunction"; - -patch spawnUri(String uri) native "isolate_spawnUri"; - -patch class Timer { - /* patch */ factory Timer(int milliseconds, void callback(Timer timer)) { - if (_TimerFactory._factory == null) { - throw new UnsupportedError("Timer interface not supported."); +patch class _Isolate { + /* patch */ static ReceivePort get port { + if (_portInternal == null) { + _portInternal = _getPortInternal(); } - return _TimerFactory._factory(milliseconds, callback, false); + return _portInternal; } - /** - * Creates a new repeating timer. The [callback] is invoked every - * [milliseconds] millisecond until cancelled. - */ - /* patch */ factory Timer.repeating(int milliseconds, - void callback(Timer timer)) { - if (_TimerFactory._factory == null) { - throw new UnsupportedError("Timer interface not supported."); - } - return _TimerFactory._factory(milliseconds, callback, true); - } -} + /* patch */ static spawnFunction(void topLevelFunction(), + [bool UnhandledExceptionCallback(IsolateUnhandledException e)]) + native "isolate_spawnFunction"; -typedef Timer _TimerFactoryClosure(int milliseconds, - void callback(Timer timer), - bool repeating); - -class _TimerFactory { - static _TimerFactoryClosure _factory; -} - -// TODO(ahe): Warning: this is NOT called by Dartium. Instead, it sets -// [_TimerFactory._factory] directly. -void _setTimerFactoryClosure(_TimerFactoryClosure closure) { - _TimerFactory._factory = closure; + /* patch */ static spawnUri(String uri) native "isolate_spawnUri"; } diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart index 52818a42dca..4168db328e6 100644 --- a/runtime/lib/math_patch.dart +++ b/runtime/lib/math_patch.dart @@ -51,7 +51,7 @@ patch class Random { class _Random implements Random { // Internal state of the random number generator. - final _state = new List(2); + final _state = new List.fixedLength(2); static const kSTATE_LO = 0; static const kSTATE_HI = 1; diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart index 8b57657778c..6e4f76162d0 100644 --- a/runtime/lib/mirrors_impl.dart +++ b/runtime/lib/mirrors_impl.dart @@ -156,8 +156,8 @@ abstract class _LocalObjectMirrorImpl extends _LocalVMObjectMirrorImpl try { completer.complete( _invoke(this, memberName, positionalArguments)); - } catch (exception) { - completer.completeException(exception); + } catch (exception, s) { + completer.completeError(exception, s); } return completer.future; } @@ -167,8 +167,8 @@ abstract class _LocalObjectMirrorImpl extends _LocalVMObjectMirrorImpl Completer completer = new Completer(); try { completer.complete(_getField(this, fieldName)); - } catch (exception) { - completer.completeException(exception); + } catch (exception, s) { + completer.completeError(exception, s); } return completer.future; } @@ -180,8 +180,8 @@ abstract class _LocalObjectMirrorImpl extends _LocalVMObjectMirrorImpl Completer completer = new Completer(); try { completer.complete(_setField(this, fieldName, arg)); - } catch (exception) { - completer.completeException(exception); + } catch (exception, s) { + completer.completeError(exception, s); } return completer.future; } diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc index a1e029e4103..674ab645b54 100644 --- a/runtime/lib/regexp.cc +++ b/runtime/lib/regexp.cc @@ -19,8 +19,8 @@ DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 4) { GET_NON_NULL_NATIVE_ARGUMENT( Instance, handle_multi_line, arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT( - Instance, handle_ignore_case, arguments->NativeArgAt(3)); - bool ignore_case = handle_ignore_case.raw() == Bool::True().raw(); + Instance, handle_case_sensitive, arguments->NativeArgAt(3)); + bool ignore_case = handle_case_sensitive.raw() != Bool::True().raw(); bool multi_line = handle_multi_line.raw() == Bool::True().raw(); return Jscre::Compile(pattern, multi_line, ignore_case); } @@ -33,17 +33,17 @@ DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_getPattern, 1) { } -DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_multiLine, 1) { +DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_getIsMultiLine, 1) { const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->NativeArgAt(0)); ASSERT(!regexp.IsNull()); return Bool::Get(regexp.is_multi_line()); } -DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_ignoreCase, 1) { +DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_getIsCaseSensitive, 1) { const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->NativeArgAt(0)); ASSERT(!regexp.IsNull()); - return Bool::Get(regexp.is_ignore_case()); + return Bool::Get(!regexp.is_ignore_case()); } diff --git a/runtime/lib/regexp_patch.dart b/runtime/lib/regexp_patch.dart index 6a921fa9a07..2eab296397e 100644 --- a/runtime/lib/regexp_patch.dart +++ b/runtime/lib/regexp_patch.dart @@ -5,10 +5,10 @@ patch class RegExp { /* patch */ factory RegExp(String pattern, {bool multiLine: false, - bool ignoreCase: false}) { + bool caseSensitive: true}) { return new _JSSyntaxRegExp(pattern, multiLine: multiLine, - ignoreCase: ignoreCase); + caseSensitive: caseSensitive); } } @@ -44,7 +44,7 @@ class _JSRegExpMatch implements Match { } List groups(List groupsSpec) { - var groupsList = new List(groupsSpec.length); + var groupsList = new List.fixedLength(groupsSpec.length); for (int i = 0; i < groupsSpec.length; i++) { groupsList[i] = group(groupsSpec[i]); } @@ -66,7 +66,7 @@ class _JSSyntaxRegExp implements RegExp { factory _JSSyntaxRegExp( String pattern, {bool multiLine: false, - bool ignoreCase: false}) native "JSSyntaxRegExp_factory"; + bool caseSensitive: true}) native "JSSyntaxRegExp_factory"; Match firstMatch(String str) { List match = _ExecuteMatch(str, 0); @@ -114,9 +114,9 @@ class _JSSyntaxRegExp implements RegExp { String get pattern native "JSSyntaxRegExp_getPattern"; - bool get multiLine native "JSSyntaxRegExp_multiLine"; + bool get isMultiLine native "JSSyntaxRegExp_getIsMultiLine"; - bool get ignoreCase native "JSSyntaxRegExp_ignoreCase"; + bool get isCaseSensitive native "JSSyntaxRegExp_getIsCaseSensitive"; int get _groupCount native "JSSyntaxRegExp_getGroupCount"; diff --git a/runtime/lib/string_base.dart b/runtime/lib/string_base.dart index 3d2484e17b6..1f6d9fe7bfd 100644 --- a/runtime/lib/string_base.dart +++ b/runtime/lib/string_base.dart @@ -155,6 +155,41 @@ class _StringBase { return _substringUnchecked(startIndex, endIndex); } + String slice([int startIndex, int endIndex]) { + int start, end; + if (startIndex == null) { + start = 0; + } else if (startIndex is! int) { + throw new ArgumentError("startIndex is not int"); + } else if (startIndex >= 0) { + start = startIndex; + } else { + start = this.length + startIndex; + } + if (start < 0 || start > this.length) { + throw new RangeError( + "startIndex out of range: $startIndex (length: $length)"); + } + if (endIndex == null) { + end = this.length; + } else if (endIndex is! int) { + throw new ArgumentError("endIndex is not int"); + } else if (endIndex >= 0) { + end = endIndex; + } else { + end = this.length + endIndex; + } + if (end < 0 || end > this.length) { + throw new RangeError( + "endIndex out of range: $endIndex (length: $length)"); + } + if (end < start) { + throw new ArgumentError( + "End before start: $endIndex < $startIndex (length: $length)"); + } + return _substringUnchecked(start, end); + } + String _substringUnchecked(int startIndex, int endIndex) { assert(endIndex != null); assert((startIndex >= 0) && (startIndex <= this.length)); @@ -204,7 +239,7 @@ class _StringBase { if (pattern is String) { return indexOf(pattern, startIndex) >= 0; } - return pattern.allMatches(this.substring(startIndex)).iterator().hasNext; + return pattern.allMatches(this.substring(startIndex)).iterator.moveNext(); } String replaceFirst(Pattern pattern, String replacement) { @@ -216,9 +251,9 @@ class _StringBase { } StringBuffer buffer = new StringBuffer(); int startIndex = 0; - Iterator iterator = pattern.allMatches(this).iterator(); - if (iterator.hasNext) { - Match match = iterator.next(); + Iterator iterator = pattern.allMatches(this).iterator; + if (iterator.moveNext()) { + Match match = iterator.current; buffer..add(this.substring(startIndex, match.start)) ..add(replacement); startIndex = match.end; @@ -231,7 +266,8 @@ class _StringBase { throw new ArgumentError("${pattern} is not a Pattern"); } if (replacement is! String) { - throw new ArgumentError("${replacement} is not a String"); + throw new ArgumentError( + "${replacement} is not a String or Match->String function"); } StringBuffer buffer = new StringBuffer(); int startIndex = 0; @@ -243,13 +279,75 @@ class _StringBase { return (buffer..add(this.substring(startIndex))).toString(); } + String replaceAllMapped(Pattern pattern, String replace(Match match)) { + return splitMapJoin(pattern, onMatch: replace); + } + + static String _matchString(Match match) => match[0]; + static String _stringIdentity(String string) => string; + + String _splitMapJoinEmptyString(String onMatch(Match match), + String onNonMatch(String nonMatch)) { + // Pattern is the empty string. + StringBuffer buffer = new StringBuffer(); + int length = this.length; + int i = 0; + buffer.add(onNonMatch("")); + while (i < length) { + buffer.add(onMatch(new _StringMatch(i, this, ""))); + // Special case to avoid splitting a surrogate pair. + int code = this.charCodeAt(i); + if ((code & ~0x3FF) == 0xD800 && length > i + 1) { + // Leading surrogate; + code = this.charCodeAt(i + 1); + if ((code & ~0x3FF) == 0xDC00) { + // Matching trailing surrogate. + buffer.add(onNonMatch(this.substring(i, i + 2))); + i += 2; + continue; + } + } + buffer.add(onNonMatch(this[i])); + i++; + } + buffer.add(onMatch(new _StringMatch(i, this, ""))); + buffer.add(onNonMatch("")); + return buffer.toString(); + } + + String splitMapJoin(Pattern pattern, + {String onMatch(Match match), + String onNonMatch(String nonMatch)}) { + if (pattern is! Pattern) { + throw new ArgumentError("${pattern} is not a Pattern"); + } + if (onMatch == null) onMatch = _matchString; + if (onNonMatch == null) onNonMatch = _stringIdentity; + if (pattern is String) { + String stringPattern = pattern; + if (stringPattern.isEmpty) { + return _splitMapJoinEmptyString(onMatch, onNonMatch); + } + } + StringBuffer buffer = new StringBuffer(); + int startIndex = 0; + for (Match match in pattern.allMatches(this)) { + buffer.add(onNonMatch(this.substring(startIndex, match.start))); + buffer.add(onMatch(match).toString()); + startIndex = match.end; + } + buffer.add(onNonMatch(this.substring(startIndex))); + return buffer.toString(); + } + + /** * Convert all objects in [values] to strings and concat them * into a result string. */ static String _interpolate(List values) { int numValues = values.length; - var stringList = new List(numValues); + var stringList = new List.fixedLength(numValues); for (int i = 0; i < numValues; i++) { stringList[i] = values[i].toString(); } @@ -284,8 +382,8 @@ class _StringBase { return splitChars(); } int length = this.length; - Iterator iterator = pattern.allMatches(this).iterator(); - if (length == 0 && iterator.hasNext) { + Iterator iterator = pattern.allMatches(this).iterator; + if (length == 0 && iterator.moveNext()) { // A matched empty string input returns the empty list. return []; } @@ -293,11 +391,11 @@ class _StringBase { int startIndex = 0; int previousIndex = 0; while (true) { - if (startIndex == length || !iterator.hasNext) { + if (startIndex == length || !iterator.moveNext()) { result.add(this._substringUnchecked(previousIndex, length)); break; } - Match match = iterator.next(); + Match match = iterator.current; if (match.start == length) { result.add(this._substringUnchecked(previousIndex, length)); break; @@ -315,7 +413,7 @@ class _StringBase { List splitChars() { int len = this.length; - final result = new List(len); + final result = new List.fixedLength(len); for (int i = 0; i < len; i++) { result[i] = this[i]; } @@ -324,7 +422,7 @@ class _StringBase { List get charCodes { int len = this.length; - final result = new List(len); + final result = new List.fixedLength(len); for (int i = 0; i < len; i++) { result[i] = this.charCodeAt(i); } @@ -336,34 +434,38 @@ class _StringBase { String toLowerCase() native "String_toLowerCase"; // Implementations of Strings methods follow below. - static String join(List strings, String separator) { - final int length = strings.length; - if (length == 0) { - return ""; - } - - List stringsList = strings; - if (separator.length != 0) { - stringsList = new List(2 * length - 1); - stringsList[0] = strings[0]; - int j = 1; - for (int i = 1; i < length; i++) { - stringsList[j++] = separator; - stringsList[j++] = strings[i]; + static String join(Iterable strings, String separator) { + bool first = true; + List stringsList = []; + for (String string in strings) { + if (first) { + first = false; + } else { + stringsList.add(separator); } + + if (string is! String) { + throw new ArgumentError(Error.safeToString(string)); + } + stringsList.add(string); } return concatAll(stringsList); } - static String concatAll(List strings) { + static String concatAll(Iterable strings) { _ObjectArray stringsArray; if (strings is _ObjectArray) { stringsArray = strings; + for (int i = 0; i < strings.length; i++) { + if (strings[i] is! String) throw new ArgumentError(strings[i]); + } } else { int len = strings.length; stringsArray = new _ObjectArray(len); - for (int i = 0; i < len; i++) { - stringsArray[i] = strings[i]; + int i = 0; + for (String string in strings) { + if (string is! String) throw new ArgumentError(string); + stringsArray[i++] = string; } } return _concatAll(stringsArray); diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart index df0393db3f4..7157ff9a13a 100644 --- a/runtime/lib/string_patch.dart +++ b/runtime/lib/string_patch.dart @@ -9,7 +9,7 @@ patch class String { } patch class Strings { - /* patch */ static String join(List strings, String separator) { + /* patch */ static String join(Iterable strings, String separator) { return _StringBase.join(strings, separator); } diff --git a/runtime/lib/timer_patch.dart b/runtime/lib/timer_patch.dart new file mode 100644 index 00000000000..d27e4e88994 --- /dev/null +++ b/runtime/lib/timer_patch.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2012, 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. + +patch class Timer { + /* patch */ factory Timer(int milliseconds, void callback(Timer timer)) { + if (_TimerFactory._factory == null) { + throw new UnsupportedError("Timer interface not supported."); + } + return _TimerFactory._factory(milliseconds, callback, false); + } + + /** + * Creates a new repeating timer. The [callback] is invoked every + * [milliseconds] millisecond until cancelled. + */ + /* patch */ factory Timer.repeating(int milliseconds, + void callback(Timer timer)) { + if (_TimerFactory._factory == null) { + throw new UnsupportedError("Timer interface not supported."); + } + return _TimerFactory._factory(milliseconds, callback, true); + } +} + +typedef Timer _TimerFactoryClosure(int milliseconds, + void callback(Timer timer), + bool repeating); + +class _TimerFactory { + static _TimerFactoryClosure _factory; +} + +// TODO(ahe): Warning: this is NOT called by Dartium. Instead, it sets +// [_TimerFactory._factory] directly. +void _setTimerFactoryClosure(_TimerFactoryClosure closure) { + _TimerFactory._factory = closure; +} diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart index d4b8b88b8cc..26bc3ddf50e 100644 --- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart +++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart @@ -9,6 +9,7 @@ library isolate_mirror_local_test; +import 'dart:async'; import 'dart:isolate'; import 'dart:mirrors'; @@ -125,7 +126,7 @@ void testRootLibraryMirror(LibraryMirror lib_mirror) { }); // Check that the members map is complete. - List keys = lib_mirror.members.keys; + List keys = lib_mirror.members.keys.toList(); sort(keys); Expect.equals('[' 'FuncType, ' @@ -162,7 +163,7 @@ void testRootLibraryMirror(LibraryMirror lib_mirror) { '$keys'); // Check that the classes map is complete. - keys = lib_mirror.classes.keys; + keys = lib_mirror.classes.keys.toList(); sort(keys); Expect.equals('[' 'FuncType, ' @@ -174,7 +175,7 @@ void testRootLibraryMirror(LibraryMirror lib_mirror) { '$keys'); // Check that the functions map is complete. - keys = lib_mirror.functions.keys; + keys = lib_mirror.functions.keys.toList(); sort(keys); Expect.equals('[' '_stringCompare, ' @@ -200,17 +201,17 @@ void testRootLibraryMirror(LibraryMirror lib_mirror) { '$keys'); // Check that the getters map is complete. - keys = lib_mirror.getters.keys; + keys = lib_mirror.getters.keys.toList(); sort(keys); Expect.equals('[myVar]', '$keys'); // Check that the setters map is complete. - keys = lib_mirror.setters.keys; + keys = lib_mirror.setters.keys.toList(); sort(keys); Expect.equals('[myVar=]', '$keys'); // Check that the variables map is complete. - keys = lib_mirror.variables.keys; + keys = lib_mirror.variables.keys.toList(); sort(keys); Expect.equals('[' 'exit_port, ' @@ -458,59 +459,47 @@ void methodWithError() { void testMirrorErrors(MirrorSystem mirrors) { LibraryMirror lib_mirror = mirrors.isolate.rootLibrary; - Future future = - lib_mirror.invoke('methodWithException', []); - future.handleException( - (MirroredError exc) { - Expect.isTrue(exc is MirroredUncaughtExceptionError); + lib_mirror.invoke('methodWithException', []) + .then((InstanceMirror retval) { + // Should not reach here. + Expect.isTrue(false); + }) + .catchError((exc) { + Expect.isTrue(exc.error is MirroredUncaughtExceptionError); Expect.equals('MyException', - exc.exception_mirror.type.simpleName); + exc.error.exception_mirror.type.simpleName); Expect.equals('MyException: from methodWithException', - exc.exception_string); - Expect.isTrue(exc.stacktrace.toString().contains( + exc.error.exception_string); + Expect.isTrue(exc.error.stacktrace.toString().contains( 'isolate_mirror_local_test.dart')); testDone('testMirrorErrors1'); - return true; - }); - future.then( - (InstanceMirror retval) { - // Should not reach here. - Expect.isTrue(false); }); - Future future2 = - lib_mirror.invoke('methodWithError', []); - future2.handleException( - (MirroredError exc) { - Expect.isTrue(exc is MirroredCompilationError); - Expect.isTrue(exc.message.contains('unexpected token')); - testDone('testMirrorErrors2'); - return true; - }); - future2.then( - (InstanceMirror retval) { - // Should not reach here. - Expect.isTrue(false); - }); + lib_mirror.invoke('methodWithError', []) + .then((InstanceMirror retval) { + // Should not reach here. + Expect.isTrue(false); + }) + .catchError((exc) { + Expect.isTrue(exc.error is MirroredCompilationError); + Expect.isTrue(exc.error.message.contains('unexpected token')); + testDone('testMirrorErrors2'); + }); // TODO(turnidge): When we call a method that doesn't exist, we // should probably call noSuchMethod(). I'm adding this test to // document the current behavior in the meantime. - Future future3 = - lib_mirror.invoke('methodNotFound', []); - future3.handleException( - (MirroredError exc) { - Expect.isTrue(exc is MirroredCompilationError); - Expect.isTrue(exc.message.contains( - "did not find top-level function 'methodNotFound'")); - testDone('testMirrorErrors3'); - return true; - }); - future3.then( - (InstanceMirror retval) { - // Should not reach here. - Expect.isTrue(false); - }); + lib_mirror.invoke('methodNotFound', []) + .then((InstanceMirror retval) { + // Should not reach here. + Expect.isTrue(false); + }) + .catchError((exc) { + Expect.isTrue(exc.error is MirroredCompilationError); + Expect.isTrue(exc.error.message.contains( + "did not find top-level function 'methodNotFound'")); + testDone('testMirrorErrors3'); + }); } void main() { diff --git a/runtime/tests/vm/dart/isolate_unhandled_exception_test.dart b/runtime/tests/vm/dart/isolate_unhandled_exception_test.dart index 7bab730504d..30f36b3a772 100644 --- a/runtime/tests/vm/dart/isolate_unhandled_exception_test.dart +++ b/runtime/tests/vm/dart/isolate_unhandled_exception_test.dart @@ -35,14 +35,15 @@ void main() { // Send a message that will cause an ignorable exception to be thrown. Future f = isolate_port.call('throw exception'); - f.onComplete((future) { + f.catchError((error) { // Exception wasn't ignored as it was supposed to be. - Expect.equals(null, future.exception); + Expect.fail("Error not expected"); }); // Verify that isolate can still handle messages. - isolate_port.call('hi').onComplete((future) { - Expect.equals(null, future.exception); - Expect.equals('hello', future.value); + isolate_port.call('hi').then((value) { + Expect.equals('hello', value); + }, onError: (error) { + Expect.fail("Error not expected"); }); } diff --git a/runtime/tests/vm/dart/isolate_unhandled_exception_uri_test.dart b/runtime/tests/vm/dart/isolate_unhandled_exception_uri_test.dart index da7ee50f9fe..00f990421de 100644 --- a/runtime/tests/vm/dart/isolate_unhandled_exception_uri_test.dart +++ b/runtime/tests/vm/dart/isolate_unhandled_exception_uri_test.dart @@ -18,14 +18,15 @@ void main() { // Send a message that will cause an ignorable exception to be thrown. Future f = isolate_port.call('throw exception'); - f.onComplete((future) { - Expect.equals(null, future.exception); + f.catchError((error) { + Expect.fail("Error not expected"); }); // Verify that isolate can still handle messages. - isolate_port.call('hi').onComplete((future) { - Expect.equals(null, future.exception); - Expect.equals('hello', future.value); + isolate_port.call('hi').then((value) { + Expect.equals('hello', value); + }, onError: (error) { + Expect.fail("Error not expected"); }); } diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status index 0288b213084..17e6cb32f32 100644 --- a/runtime/tests/vm/vm.status +++ b/runtime/tests/vm/vm.status @@ -42,3 +42,9 @@ dart/*: Skip [ $arch == simarm ] dart/*: Skip + +# TODO(ajohnsen): Fix this as part of library changes. +[ $compiler == none ] +cc/CustomIsolates: Skip # Bug 6890 +cc/NewNativePort: Skip # Bug 6890 +cc/RunLoop_ExceptionParent: Skip # Bug 6890 diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc index bab1d4b0d89..d0e864cea63 100644 --- a/runtime/vm/bootstrap.cc +++ b/runtime/vm/bootstrap.cc @@ -26,6 +26,13 @@ RawScript* Bootstrap::LoadScript(const char* url, } +RawScript* Bootstrap::LoadASyncScript(bool patch) { + const char* url = patch ? "dart:async-patch" : "dart:async"; + const char* source = patch ? async_patch_ : async_source_; + return LoadScript(url, source, patch); +} + + RawScript* Bootstrap::LoadCoreScript(bool patch) { // TODO(iposva): Use proper library name. const char* url = patch ? "dart:core-patch" : "bootstrap"; diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h index 2668b610e35..55097321e7c 100644 --- a/runtime/vm/bootstrap.h +++ b/runtime/vm/bootstrap.h @@ -17,6 +17,7 @@ class Script; class Bootstrap : public AllStatic { public: + static RawScript* LoadASyncScript(bool patch); static RawScript* LoadCoreScript(bool patch); static RawScript* LoadCollectionScript(bool patch); static RawScript* LoadMathScript(bool patch); @@ -29,6 +30,8 @@ class Bootstrap : public AllStatic { private: static RawScript* LoadScript(const char* url, const char* source, bool patch); + static const char async_source_[]; + static const char async_patch_[]; static const char corelib_source_[]; static const char corelib_patch_[]; static const char collection_source_[]; diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc index 9978bf7081c..164b33d9a02 100644 --- a/runtime/vm/bootstrap_natives.cc +++ b/runtime/vm/bootstrap_natives.cc @@ -56,6 +56,10 @@ void Bootstrap::SetupNativeResolver() { Dart_NativeEntryResolver resolver = reinterpret_cast(BootstrapNatives::Lookup); + library = Library::ASyncLibrary(); + ASSERT(!library.IsNull()); + library.set_native_entry_resolver(resolver); + library = Library::CoreLibrary(); ASSERT(!library.IsNull()); library.set_native_entry_resolver(resolver); diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index fec7c9d50fd..5b1b6adef7c 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -67,8 +67,8 @@ namespace dart { V(Double_pow, 2) \ V(JSSyntaxRegExp_factory, 4) \ V(JSSyntaxRegExp_getPattern, 1) \ - V(JSSyntaxRegExp_multiLine, 1) \ - V(JSSyntaxRegExp_ignoreCase, 1) \ + V(JSSyntaxRegExp_getIsMultiLine, 1) \ + V(JSSyntaxRegExp_getIsCaseSensitive, 1) \ V(JSSyntaxRegExp_getGroupCount, 1) \ V(JSSyntaxRegExp_ExecuteMatch, 3) \ V(ObjectArray_allocate, 2) \ diff --git a/runtime/vm/bootstrap_nocorelib.cc b/runtime/vm/bootstrap_nocorelib.cc index fb3b8ed00c3..6d543db7118 100644 --- a/runtime/vm/bootstrap_nocorelib.cc +++ b/runtime/vm/bootstrap_nocorelib.cc @@ -15,6 +15,12 @@ namespace dart { DEFINE_FLAG(bool, print_bootstrap, false, "Print the bootstrap source."); +RawScript* Bootstrap::LoadASyncScript(bool is_patch) { + UNREACHABLE(); + return Script::null(); +} + + RawScript* Bootstrap::LoadCoreScript(bool is_patch) { UNREACHABLE(); return Script::null(); diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc index 81aa6077dbe..ad6dec62084 100644 --- a/runtime/vm/custom_isolate_test.cc +++ b/runtime/vm/custom_isolate_test.cc @@ -24,6 +24,7 @@ static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc); static const char* kCustomIsolateScriptChars = + "import 'dart:async';\n" "import 'dart:isolate';\n" "\n" "ReceivePort mainPort;\n" diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc index 85f58857f11..ad8eab99b93 100644 --- a/runtime/vm/exceptions.cc +++ b/runtime/vm/exceptions.cc @@ -414,6 +414,10 @@ RawObject* Exceptions::Create(ExceptionType type, const Array& arguments) { library = Library::CoreLibrary(); class_name = &Symbols::FormatException(); break; + case kUnsupported: + library = Library::CoreLibrary(); + class_name = &Symbols::UnsupportedError(); + break; case kStackOverflow: library = Library::CoreLibrary(); class_name = &Symbols::StackOverflowError(); diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h index 794801b7718..9582034f150 100644 --- a/runtime/vm/exceptions.h +++ b/runtime/vm/exceptions.h @@ -53,6 +53,7 @@ class Exceptions : AllStatic { kArgument, kNoSuchMethod, kFormat, + kUnsupported, kStackOverflow, kOutOfMemory, kInternalError, diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc index 3b6a97d5768..a7e52f8f305 100644 --- a/runtime/vm/flow_graph_builder.cc +++ b/runtime/vm/flow_graph_builder.cc @@ -1819,9 +1819,7 @@ static intptr_t GetResultCidOfConstructor(ConstructorCallNode* node) { // GrowableObjectArray. However if there is an argument the result // is not guaranteed to be a fixed size array because the argument // can be null. - if (node->arguments()->length() == 0) { - return kGrowableObjectArrayCid; - } + return kGrowableObjectArrayCid; } else { if (IsRecognizedConstructor(function, Symbols::ObjectArray()) && (node->arguments()->length() == 1)) { diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h index 61883638cb8..d6d28370590 100644 --- a/runtime/vm/intrinsifier.h +++ b/runtime/vm/intrinsifier.h @@ -78,9 +78,6 @@ namespace dart { V(::, sin, Math_sin, 1273932041) \ V(::, cos, Math_cos, 1749547468) \ V(Object, ==, Object_equal, 2126956595) \ - V(_FixedSizeArrayIterator, get:hasNext, \ - FixedSizeArrayIterator_getHasNext, 682147711) \ - V(_FixedSizeArrayIterator, next, FixedSizeArrayIterator_next, 1283926262) \ V(_StringBase, get:hashCode, String_getHashCode, 320803993) \ V(_StringBase, get:isEmpty, String_getIsEmpty, 711547329) \ V(_StringBase, get:length, String_getLength, 320803993) \ @@ -104,6 +101,9 @@ namespace dart { V(_Float64Array, []=, Float64Array_setIndexed, 1948811847) \ V(_ExternalUint8Array, [], ExternalUint8Array_getIndexed, 753790851) \ +// TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and +// _FixedSizeArrayIterator, moveNext. + // Forward declarations. class Assembler; class Function; diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc index 9952aa91b54..05b711629b0 100644 --- a/runtime/vm/intrinsifier_arm.cc +++ b/runtime/vm/intrinsifier_arm.cc @@ -295,16 +295,6 @@ bool Intrinsifier::Object_equal(Assembler* assembler) { } -bool Intrinsifier::FixedSizeArrayIterator_next(Assembler* assembler) { - return false; -} - - -bool Intrinsifier::FixedSizeArrayIterator_getHasNext(Assembler* assembler) { - return false; -} - - bool Intrinsifier::String_getHashCode(Assembler* assembler) { return false; } diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc index 91beb272d5b..7536d63eb79 100644 --- a/runtime/vm/intrinsifier_ia32.cc +++ b/runtime/vm/intrinsifier_ia32.cc @@ -247,20 +247,6 @@ bool Intrinsifier::Array_setIndexed(Assembler* assembler) { } -static intptr_t GetOffsetForField(const char* class_name_p, - const char* field_name_p) { - const String& class_name = String::Handle(Symbols::New(class_name_p)); - const String& field_name = String::Handle(Symbols::New(field_name_p)); - const Library& core_lib = Library::Handle(Library::CoreLibrary()); - const Class& cls = - Class::Handle(core_lib.LookupClassAllowPrivate(class_name)); - ASSERT(!cls.IsNull()); - const Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name)); - ASSERT(!field.IsNull()); - return field.Offset(); -} - - // Allocate a GrowableObjectArray using the backing array specified. // On stack: type argument (+2), data (+1), return-address (+0). bool Intrinsifier::GArray_Allocate(Assembler* assembler) { @@ -1619,85 +1605,6 @@ bool Intrinsifier::Object_equal(Assembler* assembler) { } -static const char* kFixedSizeArrayIteratorClassName = "_FixedSizeArrayIterator"; - - -// Class 'FixedSizeArrayIterator': -// T next() { -// return _array[_pos++]; -// } -// Intrinsify: return _array[_pos++]; -// TODO(srdjan): Throw a 'StateError' exception if the iterator -// has no more elements. -bool Intrinsifier::FixedSizeArrayIterator_next(Assembler* assembler) { - Label fall_through; - intptr_t array_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_array"); - intptr_t pos_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); - ASSERT(array_offset >= 0 && pos_offset >= 0); - // Receiver is not NULL. - __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. - __ movl(EBX, FieldAddress(EAX, pos_offset)); // Field _pos. - // '_pos' cannot be greater than array length and therefore is always Smi. -#if defined(DEBUG) - Label pos_ok; - __ testl(EBX, Immediate(kSmiTagMask)); - __ j(ZERO, &pos_ok, Assembler::kNearJump); - __ Stop("pos must be Smi"); - __ Bind(&pos_ok); -#endif - // Check that we are not trying to call 'next' when 'hasNext' is false. - __ movl(EAX, FieldAddress(EAX, array_offset)); // Field _array. - __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); // Range check. - __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); - - // EBX is Smi, i.e, times 2. - ASSERT(kSmiTagShift == 1); - __ movl(EDI, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray))); // Result. - const Immediate value = Immediate(reinterpret_cast(Smi::New(1))); - __ addl(EBX, value); // _pos++. - __ j(OVERFLOW, &fall_through, Assembler::kNearJump); - __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. - __ StoreIntoObjectNoBarrier(EAX, - FieldAddress(EAX, pos_offset), - EBX); // Store _pos. - __ movl(EAX, EDI); - __ ret(); - __ Bind(&fall_through); - return false; -} - - -// Class 'FixedSizeArrayIterator': -// bool get hasNext { -// return _length > _pos; -// } -bool Intrinsifier::FixedSizeArrayIterator_getHasNext(Assembler* assembler) { - Label fall_through, is_true; - intptr_t length_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_length"); - intptr_t pos_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); - __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. - __ movl(EBX, FieldAddress(EAX, length_offset)); // Field _length. - __ movl(EAX, FieldAddress(EAX, pos_offset)); // Field _pos. - __ movl(EDI, EAX); - __ orl(EDI, EBX); - __ testl(EDI, Immediate(kSmiTagMask)); - __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi _length. - __ cmpl(EBX, EAX); // _length > _pos. - __ j(GREATER, &is_true, Assembler::kNearJump); - __ LoadObject(EAX, Bool::False()); - __ ret(); - __ Bind(&is_true); - __ LoadObject(EAX, Bool::True()); - __ ret(); - __ Bind(&fall_through); - return false; -} - - bool Intrinsifier::String_getHashCode(Assembler* assembler) { Label fall_through; __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc index bc0ea67276a..bf8261e133b 100644 --- a/runtime/vm/intrinsifier_x64.cc +++ b/runtime/vm/intrinsifier_x64.cc @@ -1479,98 +1479,6 @@ bool Intrinsifier::Object_equal(Assembler* assembler) { } -static intptr_t GetOffsetForField(const char* class_name_p, - const char* field_name_p) { - const String& class_name = String::Handle(Symbols::New(class_name_p)); - const String& field_name = String::Handle(Symbols::New(field_name_p)); - const Library& core_lib = Library::Handle(Library::CoreLibrary()); - const Class& cls = - Class::Handle(core_lib.LookupClassAllowPrivate(class_name)); - ASSERT(!cls.IsNull()); - const Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name)); - ASSERT(!field.IsNull()); - return field.Offset(); -} - - -static const char* kFixedSizeArrayIteratorClassName = "_FixedSizeArrayIterator"; - -// Class 'FixedSizeArrayIterator': -// T next() { -// return _array[_pos++]; -// } -// Intrinsify: return _array[_pos++]; -// TODO(srdjan): Throw a 'StateError' exception if the iterator -// has no more elements. -bool Intrinsifier::FixedSizeArrayIterator_next(Assembler* assembler) { - Label fall_through; - const intptr_t array_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_array"); - const intptr_t pos_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); - ASSERT((array_offset >= 0) && (pos_offset >= 0)); - // Receiver is not NULL. - __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. - __ movq(RCX, FieldAddress(RAX, pos_offset)); // Field _pos. - // '_pos' cannot be greater than array length and therefore is always Smi. -#if defined(DEBUG) - Label pos_ok; - __ testq(RCX, Immediate(kSmiTagMask)); - __ j(ZERO, &pos_ok, Assembler::kNearJump); - __ Stop("pos must be Smi"); - __ Bind(&pos_ok); -#endif - // Check that we are not trying to call 'next' when 'hasNext' is false. - __ movq(RAX, FieldAddress(RAX, array_offset)); // Field _array. - __ cmpq(RCX, FieldAddress(RAX, Array::length_offset())); // Range check. - __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); - - // RCX is Smi, i.e, times 2. - ASSERT(kSmiTagShift == 1); - __ movq(RDI, FieldAddress(RAX, RCX, TIMES_4, sizeof(RawArray))); // Result. - const Immediate value = Immediate(reinterpret_cast(Smi::New(1))); - __ addq(RCX, value); // _pos++. - __ j(OVERFLOW, &fall_through, Assembler::kNearJump); - __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. - __ StoreIntoObjectNoBarrier(RAX, - FieldAddress(RAX, pos_offset), - RCX); // Store _pos. - __ movq(RAX, RDI); - __ ret(); - __ Bind(&fall_through); - return false; -} - - -// Class 'FixedSizeArrayIterator': -// bool get hasNext { -// return _length > _pos; -// } -bool Intrinsifier::FixedSizeArrayIterator_getHasNext(Assembler* assembler) { - Label fall_through, is_true; - const intptr_t length_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_length"); - const intptr_t pos_offset = - GetOffsetForField(kFixedSizeArrayIteratorClassName, "_pos"); - __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. - __ movq(RCX, FieldAddress(RAX, length_offset)); // Field _length. - __ movq(RAX, FieldAddress(RAX, pos_offset)); // Field _pos. - __ movq(RDI, RAX); - __ orq(RDI, RCX); - __ testq(RDI, Immediate(kSmiTagMask)); - __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi _length/_pos. - __ cmpq(RCX, RAX); // _length > _pos. - __ j(GREATER, &is_true, Assembler::kNearJump); - __ LoadObject(RAX, Bool::False()); - __ ret(); - __ Bind(&is_true); - __ LoadObject(RAX, Bool::True()); - __ ret(); - __ Bind(&fall_through); - return false; -} - - bool Intrinsifier::String_getHashCode(Assembler* assembler) { Label fall_through; __ movq(RAX, Address(RSP, + 1 * kWordSize)); // String object. diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 8725b08a0ac..7122e16a279 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -924,6 +924,20 @@ RawError* Object::Init(Isolate* isolate) { if (!error.IsNull()) { return error.raw(); } + Library::InitASyncLibrary(isolate); + const Script& async_script = + Script::Handle(Bootstrap::LoadASyncScript(false)); + const Library& async_lib = Library::Handle(Library::ASyncLibrary()); + ASSERT(!async_lib.IsNull()); + error = Bootstrap::Compile(async_lib, async_script); + if (!error.IsNull()) { + return error.raw(); + } + patch_script = Bootstrap::LoadASyncScript(true); + error = async_lib.Patch(patch_script); + if (!error.IsNull()) { + return error.raw(); + } const Script& collection_script = Script::Handle(Bootstrap::LoadCollectionScript(false)); const Library& collection_lib = @@ -5972,6 +5986,14 @@ RawLibrary* Library::New(const String& url) { } +void Library::InitASyncLibrary(Isolate* isolate) { + const String& url = String::Handle(Symbols::New("dart:async")); + const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true)); + lib.Register(); + isolate->object_store()->set_async_library(lib); +} + + void Library::InitCoreLibrary(Isolate* isolate) { const String& core_lib_url = String::Handle(Symbols::New("dart:core")); const Library& core_lib = @@ -6023,6 +6045,10 @@ void Library::InitIsolateLibrary(Isolate* isolate) { const String& url = String::Handle(Symbols::New("dart:isolate")); const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true)); lib.Register(); + const Library& async_lib = Library::Handle(Library::ASyncLibrary()); + const Namespace& async_ns = Namespace::Handle( + Namespace::New(async_lib, Array::Handle(), Array::Handle())); + lib.AddImport(async_ns); isolate->object_store()->set_isolate_library(lib); } @@ -6035,6 +6061,10 @@ void Library::InitMirrorsLibrary(Isolate* isolate) { const Namespace& isolate_ns = Namespace::Handle( Namespace::New(isolate_lib, Array::Handle(), Array::Handle())); lib.AddImport(isolate_ns); + const Library& async_lib = Library::Handle(Library::ASyncLibrary()); + const Namespace& async_ns = Namespace::Handle( + Namespace::New(async_lib, Array::Handle(), Array::Handle())); + lib.AddImport(async_ns); const Library& wrappers_lib = Library::Handle(Library::NativeWrappersLibrary()); const Namespace& wrappers_ns = Namespace::Handle( @@ -6160,6 +6190,11 @@ void Library::Register() const { } +RawLibrary* Library::ASyncLibrary() { + return Isolate::Current()->object_store()->async_library(); +} + + RawLibrary* Library::CoreLibrary() { return Isolate::Current()->object_store()->core_library(); } diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 973109f1da4..e70b8f1da98 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -2027,6 +2027,7 @@ class Library : public Object { static RawLibrary* GetLibrary(intptr_t index); static bool IsKeyUsed(intptr_t key); + static void InitASyncLibrary(Isolate* isolate); static void InitCoreLibrary(Isolate* isolate); static void InitCollectionLibrary(Isolate* isolate); static void InitMathLibrary(Isolate* isolate); @@ -2035,6 +2036,7 @@ class Library : public Object { static void InitScalarlistLibrary(Isolate* isolate); static void InitNativeWrappersLibrary(Isolate* isolate); + static RawLibrary* ASyncLibrary(); static RawLibrary* CoreLibrary(); static RawLibrary* CollectionLibrary(); static RawLibrary* MathLibrary(); diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index d798ff0105c..97c822132c6 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -355,6 +355,11 @@ class ObjectStore { canonical_type_arguments_ = value.raw(); } + RawLibrary* async_library() const { return async_library_; } + void set_async_library(const Library& value) { + async_library_ = value.raw(); + } + RawLibrary* core_library() const { return core_library_; } void set_core_library(const Library& value) { core_library_ = value.raw(); @@ -555,6 +560,7 @@ class ObjectStore { RawClass* weak_property_class_; RawArray* symbol_table_; RawArray* canonical_type_arguments_; + RawLibrary* async_library_; RawLibrary* core_library_; RawLibrary* core_impl_library_; RawLibrary* collection_library_; diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index 22d8f7cc2ea..c8d4a4ea581 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -5591,17 +5591,18 @@ AstNode* Parser::ParseForInStatement(intptr_t forin_pos, // Generate initialization of iterator variable. ArgumentListNode* no_args = new ArgumentListNode(collection_pos); - AstNode* get_iterator = new InstanceCallNode( - collection_pos, collection_expr, Symbols::GetIterator(), no_args); + AstNode* get_iterator = new InstanceGetterNode( + collection_pos, collection_expr, Symbols::GetIterator()); AstNode* iterator_init = new StoreLocalNode(collection_pos, iterator_var, get_iterator); current_block_->statements->Add(iterator_init); // Generate while loop condition. - AstNode* iterator_has_next = new InstanceGetterNode( + AstNode* iterator_moveNext = new InstanceCallNode( collection_pos, new LoadLocalNode(collection_pos, iterator_var), - Symbols::HasNext()); + Symbols::MoveNext(), + no_args); // Parse the for loop body. Ideally, we would use ParseNestedStatement() // here, but that does not work well because we have to insert an implicit @@ -5610,11 +5611,10 @@ AstNode* Parser::ParseForInStatement(intptr_t forin_pos, OpenLoopBlock(); current_block_->scope->AddLabel(label); - AstNode* iterator_next = new InstanceCallNode( + AstNode* iterator_current = new InstanceGetterNode( collection_pos, new LoadLocalNode(collection_pos, iterator_var), - Symbols::Next(), - no_args); + Symbols::Current()); // Generate assignment of next iterator value to loop variable. AstNode* loop_var_assignment = NULL; @@ -5622,13 +5622,13 @@ AstNode* Parser::ParseForInStatement(intptr_t forin_pos, // The for loop declares a new variable. Add it to the loop body scope. current_block_->scope->AddVariable(loop_var); loop_var_assignment = - new StoreLocalNode(loop_var_pos, loop_var, iterator_next); + new StoreLocalNode(loop_var_pos, loop_var, iterator_current); } else { AstNode* loop_var_primary = ResolveIdent(loop_var_pos, *loop_var_name, false); ASSERT(!loop_var_primary->IsPrimaryNode()); loop_var_assignment = - CreateAssignmentNode(loop_var_primary, iterator_next); + CreateAssignmentNode(loop_var_primary, iterator_current); if (loop_var_assignment == NULL) { ErrorMsg(loop_var_pos, "variable or field '%s' is not assignable", loop_var_name->ToCString()); @@ -5651,7 +5651,7 @@ AstNode* Parser::ParseForInStatement(intptr_t forin_pos, SequenceNode* for_loop_statement = CloseBlock(); AstNode* while_statement = - new WhileNode(forin_pos, label, iterator_has_next, for_loop_statement); + new WhileNode(forin_pos, label, iterator_moveNext, for_loop_statement); current_block_->statements->Add(while_statement); return CloseBlock(); // Implicit block around while loop. diff --git a/runtime/vm/snapshot_test.dart b/runtime/vm/snapshot_test.dart index 2ba9fa28820..97a933ba652 100644 --- a/runtime/vm/snapshot_test.dart +++ b/runtime/vm/snapshot_test.dart @@ -103,7 +103,8 @@ class TowersDisk { class Towers { List piles; int movesDone; - Towers(int disks) : piles = new List(3), movesDone = 0 { + Towers(int disks) + : piles = new List.fixedLength(3), movesDone = 0 { build(0, disks); } @@ -176,7 +177,7 @@ class SieveBenchmark extends BenchmarkBase { static int sieve(int size) { int primeCount = 0; - List flags = new List(size + 1); + List flags = new List.fixedLength(size + 1); for (int i = 1; i < size; i++) flags[i] = true; for (int i = 2; i < size; i++) { if (flags[i]) { @@ -234,7 +235,7 @@ class Permute { int permute(int size) { permuteCount = 0; - List list = new List(size); + List list = new List.fixedLength(size); for (int i = 1; i < size; i++) list[i] = i - 1; doPermute(size - 1, list); return permuteCount; @@ -297,10 +298,10 @@ class Queens { } static void queens() { - List a = new List(9); - List b = new List(17); - List c = new List(15); - List x = new List(9); + List a = new List.fixedLength(9); + List b = new List.fixedLength(17); + List c = new List.fixedLength(15); + List x = new List.fixedLength(9); b[1] = false; for (int i = -7; i <= 16; i++) { if ((i >= 1) && (i <= 8)) a[i] = true; @@ -406,7 +407,7 @@ class SortData { SortData(int length) { Random r = new Random(); - list = new List(length); + list = new List.fixedLength(length); for (int i = 0; i < length; i++) list[i] = r.random(); int min, max; @@ -1317,7 +1318,7 @@ message_test_main() { List local_list1 = ["Hello", "World", "Hello", 0xffffffffff]; List local_list2 = [null, local_list1, local_list1 ]; List local_list3 = [local_list2, 2.0, true, false, 0xffffffffff]; - List sendObject = new List(5); + List sendObject = new List.fixedLength(5); sendObject[0] = local_list1; sendObject[1] = sendObject; sendObject[2] = local_list2; @@ -1441,7 +1442,7 @@ class MandelbrotState { MandelbrotState() { _result = new List>(N); - _lineProcessedBy = new List(N); + _lineProcessedBy = new List.fixedLength(N); _sent = 0; _missing = N; _validated = new Completer(); @@ -1521,7 +1522,7 @@ class LineProcessorClient { List processLine(int y) { double inverseN = 2.0 / N; double Civ = y * inverseN - 1.0; - List result = new List(N); + List result = new List.fixedLength(N); for (int x = 0; x < N; x++) { double Crv = x * inverseN - 1.5; diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 274f36ef70c..26da5b51a67 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -26,8 +26,8 @@ class ObjectPointerVisitor; V(This, "this") \ V(Super, "super") \ V(Call, "call") \ - V(HasNext, "hasNext") \ - V(Next, "next") \ + V(Current, "current") \ + V(MoveNext, "moveNext") \ V(Value, "value") \ V(ExprTemp, ":expr_temp") \ V(AnonymousClosure, "") \ @@ -166,6 +166,7 @@ class ObjectPointerVisitor; V(RangeError, "RangeError") \ V(ArgumentError, "ArgumentError") \ V(FormatException, "FormatException") \ + V(UnsupportedError, "UnsupportedError") \ V(StackOverflowError, "StackOverflowError") \ V(OutOfMemoryError, "OutOfMemoryError") \ V(InternalError, "InternalError") \ diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi index 530f7f0642f..ba02d6e8755 100644 --- a/runtime/vm/vm.gypi +++ b/runtime/vm/vm.gypi @@ -5,6 +5,8 @@ { 'variables': { 'builtin_in_cc_file': '../bin/builtin_in.cc', + 'async_cc_file': '<(SHARED_INTERMEDIATE_DIR)/async_gen.cc', + 'async_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/async_patch_gen.cc', 'corelib_cc_file': '<(SHARED_INTERMEDIATE_DIR)/corelib_gen.cc', 'corelib_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/corelib_patch_gen.cc', 'collection_cc_file': '<(SHARED_INTERMEDIATE_DIR)/collection_gen.cc', @@ -82,6 +84,8 @@ 'target_name': 'libdart_lib_withcore', 'type': 'static_library', 'dependencies': [ + 'generate_async_cc_file', + 'generate_async_patch_cc_file', 'generate_corelib_cc_file', 'generate_corelib_patch_cc_file', 'generate_collection_cc_file', @@ -95,6 +99,7 @@ 'generate_scalarlist_patch_cc_file', ], 'includes': [ + '../lib/async_sources.gypi', '../lib/lib_sources.gypi', '../lib/isolate_sources.gypi', '../lib/math_sources.gypi', @@ -104,6 +109,8 @@ 'sources': [ 'bootstrap.cc', # Include generated source files. + '<(async_cc_file)', + '<(async_patch_cc_file)', '<(corelib_cc_file)', '<(corelib_patch_cc_file)', '<(collection_cc_file)', @@ -124,6 +131,7 @@ 'target_name': 'libdart_lib', 'type': 'static_library', 'includes': [ + '../lib/async_sources.gypi', '../lib/lib_sources.gypi', '../lib/isolate_sources.gypi', '../lib/math_sources.gypi', @@ -137,6 +145,62 @@ '..', ], }, + { + 'target_name': 'generate_async_cc_file', + 'type': 'none', + 'variables': { + 'async_dart': '<(SHARED_INTERMEDIATE_DIR)/async_gen.dart', + }, + 'includes': [ + '../../sdk/lib/async/async_sources.gypi', + ], + 'sources/': [ + # Exclude all .[cc|h] files. + # This is only here for reference. Excludes happen after + # variable expansion, so the script has to do its own + # exclude processing of the sources being passed. + ['exclude', '\\.cc|h$'], + ], + 'actions': [ + { + 'action_name': 'generate_async_dart', + 'inputs': [ + '../tools/concat_library.py', + '<@(_sources)', + ], + 'outputs': [ + '<(async_dart)', + ], + 'action': [ + 'python', + '<@(_inputs)', + '--output', '<(async_dart)', + ], + 'message': 'Generating ''<(async_dart)'' file.', + }, + { + 'action_name': 'generate_async_cc', + 'inputs': [ + '../tools/create_string_literal.py', + '<(builtin_in_cc_file)', + '<@(async_dart)', + ], + 'outputs': [ + '<(async_cc_file)', + ], + 'action': [ + 'python', + 'tools/create_string_literal.py', + '--output', '<(async_cc_file)', + '--input_cc', '<(builtin_in_cc_file)', + '--include', 'vm/bootstrap.h', + '--var_name', 'dart::Bootstrap::async_source_', + '<@(_sources)', + ], + 'message': 'Generating ''<(async_cc_file)'' file.' + }, + ] + }, { 'target_name': 'generate_corelib_cc_file', 'type': 'none', @@ -535,6 +599,44 @@ }, ] }, + { + 'target_name': 'generate_async_patch_cc_file', + 'type': 'none', + 'includes': [ + # Load the runtime implementation sources. + '../lib/async_sources.gypi', + ], + 'sources/': [ + # Exclude all .[cc|h] files. + # This is only here for reference. Excludes happen after + # variable expansion, so the script has to do its own + # exclude processing of the sources being passed. + ['exclude', '\\.cc|h$'], + ], + 'actions': [ + { + 'action_name': 'generate_async_patch_cc', + 'inputs': [ + '../tools/create_string_literal.py', + '<(builtin_in_cc_file)', + '<@(_sources)', + ], + 'outputs': [ + '<(async_patch_cc_file)', + ], + 'action': [ + 'python', + 'tools/create_string_literal.py', + '--output', '<(async_patch_cc_file)', + '--input_cc', '<(builtin_in_cc_file)', + '--include', 'vm/bootstrap.h', + '--var_name', 'dart::Bootstrap::async_patch_', + '<@(_sources)', + ], + 'message': 'Generating ''<(async_patch_cc_file)'' file.' + }, + ] + }, { 'target_name': 'generate_isolate_patch_cc_file', 'type': 'none', diff --git a/sdk/lib/_internal/compiler/compiler.dart b/sdk/lib/_internal/compiler/compiler.dart index 9ef6aa872ab..b5dd3dd57b8 100644 --- a/sdk/lib/_internal/compiler/compiler.dart +++ b/sdk/lib/_internal/compiler/compiler.dart @@ -4,6 +4,7 @@ library compiler; +import 'dart:async'; import 'dart:uri'; import 'implementation/apiimpl.dart'; diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart index 73c4f28ff29..f6434a018f9 100644 --- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart +++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart @@ -5,6 +5,7 @@ library leg_apiimpl; import 'dart:uri'; +import 'dart:async'; import '../compiler.dart' as api; import 'dart2jslib.dart' as leg; @@ -107,7 +108,7 @@ class Compiler extends leg.Compiler { try { // TODO(ahe): We expect the future to be complete and call value // directly. In effect, we don't support truly asynchronous API. - text = provider(translated).value; + text = deprecatedFutureValue(provider(translated)); } catch (exception) { if (node != null) { cancel("$exception", node: node); diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart index 7f3df99eab0..201817f3dfa 100644 --- a/sdk/lib/_internal/compiler/implementation/closure.dart +++ b/sdk/lib/_internal/compiler/implementation/closure.dart @@ -614,7 +614,7 @@ class ClosureTranslator extends Visitor { currentElement = oldFunctionElement; // Mark all free variables as captured and use them in the outer function. - List freeVariables = savedClosureData.freeVariableMapping.keys; + Iterable freeVariables = savedClosureData.freeVariableMapping.keys; assert(freeVariables.isEmpty || savedInsideClosure); for (Element freeElement in freeVariables) { if (capturedVariableMapping[freeElement] != null && diff --git a/sdk/lib/_internal/compiler/implementation/code_buffer.dart b/sdk/lib/_internal/compiler/implementation/code_buffer.dart index b3b48525677..c3465e8783c 100644 --- a/sdk/lib/_internal/compiler/implementation/code_buffer.dart +++ b/sdk/lib/_internal/compiler/implementation/code_buffer.dart @@ -48,8 +48,8 @@ class CodeBuffer implements StringBuffer { buffer.add(other.getText()); } - CodeBuffer addAll(Collection objects) { - for (Object obj in objects) { + CodeBuffer addAll(Iterable iterable) { + for (Object obj in iterable) { add(obj); } return this; diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart index cb1439a52e1..6dd7695e7a7 100644 --- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart +++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart @@ -221,12 +221,12 @@ class ConstantHandler extends CompilerTask { } /** - * Returns a [List] of static non final fields that need to be initialized. - * The list must be evaluated in order since the fields might depend on each - * other. + * Returns an [Iterable] of static non final fields that need to be + * initialized. The fields list must be evaluated in order since they might + * depend on each other. */ - List getStaticNonFinalFieldsForEmission() { - return initialVariableValues.keys.filter((element) { + Iterable getStaticNonFinalFieldsForEmission() { + return initialVariableValues.keys.where((element) { return element.kind == ElementKind.FIELD && !element.isInstanceMember() && !element.modifiers.isFinal(); @@ -234,12 +234,12 @@ class ConstantHandler extends CompilerTask { } /** - * Returns a [List] of static const fields that need to be initialized. The - * list must be evaluated in order since the fields might depend on each + * Returns an [Iterable] of static const fields that need to be initialized. + * The fields must be evaluated in order since they might depend on each * other. */ - List getStaticFinalFieldsForEmission() { - return initialVariableValues.keys.filter((element) { + Iterable getStaticFinalFieldsForEmission() { + return initialVariableValues.keys.where((element) { return element.kind == ElementKind.FIELD && !element.isInstanceMember() && element.modifiers.isFinal(); diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart index e16fe4e9b8e..dc77762d69a 100644 --- a/sdk/lib/_internal/compiler/implementation/compiler.dart +++ b/sdk/lib/_internal/compiler/implementation/compiler.dart @@ -537,6 +537,7 @@ abstract class Compiler implements DiagnosticListener { bool nativeTest = library.entryCompilationUnit.script.name.contains( 'dart/tests/compiler/dart2js_native'); if (nativeTest + || libraryName == 'dart:async' || libraryName == 'dart:mirrors' || libraryName == 'dart:math' || libraryName == 'dart:html' @@ -567,7 +568,10 @@ abstract class Compiler implements DiagnosticListener { void maybeEnableIsolateHelper(LibraryElement library) { String libraryName = library.uri.toString(); if (libraryName == 'dart:isolate' - || libraryName == 'dart:html') { + || libraryName == 'dart:html' + // TODO(floitsch): create a separate async-helper library instead of + // importing the isolate-library just for async. + || libraryName == 'dart:async') { importIsolateHelperLibrary(library); } } diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart index c4687ba6665..62286a07529 100644 --- a/sdk/lib/_internal/compiler/implementation/dart2js.dart +++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart @@ -4,6 +4,7 @@ library dart2js; +import 'dart:async'; import 'dart:io'; import 'dart:uri'; import 'dart:utf'; @@ -287,8 +288,8 @@ void compile(List argv) { // TODO(ahe): We expect the future to be complete and call value // directly. In effect, we don't support truly asynchronous API. - String code = api.compile(uri, libraryRoot, packageRoot, provider, handler, - options).value; + String code = deprecatedFutureValue( + api.compile(uri, libraryRoot, packageRoot, provider, handler, options)); if (code == null) { fail('Error: Compilation failed.'); } @@ -325,7 +326,7 @@ void writeString(Uri uri, String text) { String readAll(String filename) { var file = (new File(filename)).openSync(FileMode.READ); var length = file.lengthSync(); - var buffer = new List(length); + var buffer = new List.fixedLength(length); var bytes = file.readListSync(buffer, 0, length); file.closeSync(); return new String.fromCharCodes(new Utf8Decoder(buffer).decodeRest()); diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart index 4735b7b93f2..5fd489d4a9d 100644 --- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart +++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart @@ -137,7 +137,7 @@ class DartBackend extends Backend { Set processedTypes = new Set(); List workQueue = new List(); workQueue.addAll( - classMembers.keys.map((classElement) => classElement.thisType)); + classMembers.keys.mappedBy((classElement) => classElement.thisType)); workQueue.addAll(compiler.resolverWorld.isChecks); Element typeErrorElement = compiler.coreLibrary.find(new SourceString('TypeError')); @@ -210,7 +210,7 @@ class DartBackend extends Backend { } void codegen(WorkItem work) { } void processNativeClasses(Enqueuer world, - Collection libraries) { } + Iterable libraries) { } bool isUserLibrary(LibraryElement lib) { final INTERNAL_HELPERS = [ @@ -451,8 +451,8 @@ class DartBackend extends Backend { } void logResultBundleSizeInfo(Set topLevelElements) { - Collection referencedLibraries = - compiler.libraries.values.filter(isUserLibrary); + Iterable referencedLibraries = + compiler.libraries.values.where(isUserLibrary); // Sum total size of scripts in each referenced library. int nonPlatformSize = 0; for (LibraryElement lib in referencedLibraries) { @@ -561,5 +561,5 @@ compareElements(e0, e1) { return compareBy((e) => e.position().charOffset)(e0, e1); } -List sortElements(Collection elements) => +List sortElements(Iterable elements) => sorted(elements, compareElements); diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart index 44daef6b877..5c2a13e8739 100644 --- a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart +++ b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart @@ -190,7 +190,7 @@ void renamePlaceholders( sorted(functionScope.localPlaceholders, compareBy((LocalPlaceholder ph) => -ph.nodes.length)); List> currentSortedNodes = - currentSortedPlaceholders.map((ph) => ph.nodes); + currentSortedPlaceholders.mappedBy((ph) => ph.nodes).toList(); // Make room in all sorted locals list for new stuff. while (currentSortedNodes.length > allSortedLocals.length) { allSortedLocals.add(new Set()); diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart index 360800b8b5b..ebeb5cd936f 100644 --- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart +++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart @@ -2040,8 +2040,8 @@ class Elements { return a.hashCode.compareTo(b.hashCode); } - static List sortedByPosition(Collection elements) { - return new List.from(elements)..sort(compareByPosition); + static List sortedByPosition(Iterable elements) { + return elements.toList()..sort(compareByPosition); } } diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart index fa7722e75ab..38fb3164450 100644 --- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart +++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart @@ -791,8 +791,9 @@ class ArrayInitializer extends Expression { static List _convert(List expressions) { int index = 0; - return expressions.map( - (expression) => new ArrayElement(index++, expression)); + return expressions.mappedBy( + (expression) => new ArrayElement(index++, expression)) + .toList(); } } @@ -891,7 +892,8 @@ Call call(Expression target, List arguments) { } Fun fun(List parameterNames, Block body) { - return new Fun(parameterNames.map((n) => new Parameter(n)), body); + return new Fun(parameterNames.mappedBy((n) => new Parameter(n)).toList(), + body); } Assignment assign(Expression leftHandSide, Expression value) { diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart index e2c13472d37..cd95643780e 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart @@ -44,8 +44,8 @@ class OptionalParameterTypes { final List types; OptionalParameterTypes(int optionalArgumentsCount) - : names = new List(optionalArgumentsCount), - types = new List(optionalArgumentsCount); + : names = new List.fixedLength(optionalArgumentsCount), + types = new List.fixedLength(optionalArgumentsCount); int get length => names.length; SourceString name(int index) => names[index]; @@ -71,10 +71,10 @@ class HTypeList { final List namedArguments; HTypeList(int length) - : types = new List(length), + : types = new List.fixedLength(length), namedArguments = null; HTypeList.withNamedArguments(int length, this.namedArguments) - : types = new List(length); + : types = new List.fixedLength(length); const HTypeList.withAllUnknown() : types = null, namedArguments = null; diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart index 3fe765319c9..a5a1252ba7d 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart @@ -484,10 +484,12 @@ $lazyInitializerLogic // The parameters that this stub takes. List parametersBuffer = - new List(selector.argumentCount + extraArgumentCount); + new List.fixedLength( + selector.argumentCount + extraArgumentCount); // The arguments that will be passed to the real method. List argumentsBuffer = - new List(parameters.parameterCount + extraArgumentCount); + new List.fixedLength( + parameters.parameterCount + extraArgumentCount); int count = 0; if (isInterceptorClass) { @@ -1107,8 +1109,8 @@ $lazyInitializerLogic } } - Collection getTypedefChecksOn(DartType type) { - return checkedTypedefs.filter((TypedefElement typedef) { + Iterable getTypedefChecksOn(DartType type) { + return checkedTypedefs.where((TypedefElement typedef) { FunctionType typedefType = typedef.computeType(compiler).unalias(compiler); return compiler.types.isSubtype(type, typedefType); @@ -1282,12 +1284,12 @@ $lazyInitializerLogic bool isStaticFunction(Element element) => !element.isInstanceMember() && !element.isField(); - Collection elements = - compiler.codegenWorld.generatedCode.keys.filter(isStaticFunction); + Iterable elements = + compiler.codegenWorld.generatedCode.keys.where(isStaticFunction); Set pendingElementsWithBailouts = - new Set.from( - compiler.codegenWorld.generatedBailoutCode.keys.filter( - isStaticFunction)); + compiler.codegenWorld.generatedBailoutCode.keys + .where(isStaticFunction) + .toSet(); for (Element element in Elements.sortedByPosition(elements)) { js.Expression code = compiler.codegenWorld.generatedCode[element]; @@ -1576,7 +1578,7 @@ $lazyInitializerLogic void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { ConstantHandler handler = compiler.constantHandler; - List staticNonFinalFields = + Iterable staticNonFinalFields = handler.getStaticNonFinalFieldsForEmission(); for (Element element in staticNonFinalFields) { compiler.withCurrentElement(element, () { @@ -1732,8 +1734,8 @@ $lazyInitializerLogic } List argNames = - selector.getOrderedNamedArguments().map((SourceString name) => - js.string(name.slowToString())); + selector.getOrderedNamedArguments().mappedBy((SourceString name) => + js.string(name.slowToString())).toList(); String internalName = namer.invocationMirrorInternalName(selector); @@ -1753,7 +1755,7 @@ $lazyInitializerLogic js.string(internalName), new js.LiteralNumber('$type'), new js.ArrayInitializer.from( - parameters.map((param) => js.use(param.name))), + parameters.mappedBy((param) => js.use(param.name)).toList()), new js.ArrayInitializer.from(argNames)])]); js.Expression function = new js.Fun(parameters, @@ -2087,8 +2089,8 @@ if (typeof document !== 'undefined' && document.readyState !== 'complete') { void computeNeededClasses() { instantiatedClasses = - compiler.codegenWorld.instantiatedClasses.filter(computeClassFilter()); - neededClasses = new Set.from(instantiatedClasses); + compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()); + neededClasses = instantiatedClasses.toSet(); for (ClassElement element in instantiatedClasses) { for (ClassElement superclass = element.superclass; superclass != null; diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart index ac5968b9029..497ee132758 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart @@ -76,13 +76,16 @@ $lazyInitializerLogic return new js.NamedFunction( new js.VariableDeclaration(mangledName), new js.Fun( - fieldNames.map((fieldName) => new js.Parameter(fieldName)), + fieldNames + .mappedBy((fieldName) => new js.Parameter(fieldName)) + .toList(), new js.Block( - fieldNames.map((fieldName) => + fieldNames.mappedBy((fieldName) => new js.ExpressionStatement( new js.Assignment( new js.This().dot(fieldName), - new js.VariableUse(fieldName))))))); + new js.VariableUse(fieldName)))) + .toList()))); } void emitBoundClosureClassHeader(String mangledName, diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart index d8407c386f6..0bc0bc8eabb 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart @@ -161,7 +161,7 @@ function(cls, desc) { compiler.findHelper(const SourceString('convertDartClosureToJS')); String closureConverter = backend.namer.isolateAccess(converter); Set stubParameterNames = new Set.from( - stubParameters.map((param) => param.name)); + stubParameters.mappedBy((param) => param.name)); parameters.forEachParameter((Element parameter) { String name = parameter.name.slowToString(); // If [name] is not in [stubParameters], then the parameter is an optional @@ -255,7 +255,7 @@ function(cls, desc) { js.use('Object').dot('prototype').dot(methodName).dot('call') .callWith( [js.use('this')]..addAll( - parameters.map((param) => js.use(param.name)))))); + parameters.mappedBy((param) => js.use(param.name)))))); } js.Block generateMethodBodyWithPrototypeCheckForElement( @@ -298,14 +298,14 @@ function(cls, desc) { } classesWithDynamicDispatch.forEach(visit); - Collection preorderDispatchClasses = classes.filter( + List preorderDispatchClasses = classes.where( (cls) => !getDirectSubclasses(cls).isEmpty && - classesWithDynamicDispatch.contains(cls)); + classesWithDynamicDispatch.contains(cls)).toList(); if (!compiler.enableMinification) { nativeBuffer.add('// ${classes.length} classes\n'); } - Collection classesThatHaveSubclasses = classes.filter( + Iterable classesThatHaveSubclasses = classes.where( (ClassElement t) => !getDirectSubclasses(t).isEmpty); if (!compiler.enableMinification) { nativeBuffer.add('// ${classesThatHaveSubclasses.length} !leaf\n'); @@ -411,7 +411,7 @@ function(cls, desc) { // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] js.Expression table = new js.ArrayInitializer.from( - preorderDispatchClasses.map((cls) => + preorderDispatchClasses.mappedBy((cls) => new js.ArrayInitializer.from([ js.string(toNativeTag(cls)), tagDefns[cls]]))); diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart index 22289987b86..b7a5c5c3ea4 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart @@ -167,5 +167,5 @@ class TypeCheckMapping implements TypeChecks { map[cls].add(check); } - Iterator iterator() => map.keys.iterator(); + Iterator get iterator => map.keys.iterator; } diff --git a/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart new file mode 100644 index 00000000000..a8cddae958d --- /dev/null +++ b/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2012, 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. + +// Patch file for the dart:async library. + +patch class Timer { + patch factory Timer(int milliseconds, void callback(Timer timer)) { + if (!hasTimer()) { + throw new UnsupportedError("Timer interface not supported."); + } + return new TimerImpl(milliseconds, callback); + } + + /** + * Creates a new repeating timer. The [callback] is invoked every + * [milliseconds] millisecond until cancelled. + */ + patch factory Timer.repeating(int milliseconds, void callback(Timer timer)) { + if (!hasTimer()) { + throw new UnsupportedError("Timer interface not supported."); + } + return new TimerImpl.repeating(milliseconds, callback); + } +} diff --git a/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart b/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart index 53d276e0d1d..fabebbd9409 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart @@ -13,7 +13,7 @@ class ConstantMap implements Map { final List _keys; bool containsValue(V needle) { - return values.some((V value) => value == needle); + return values.any((V value) => value == needle); } bool containsKey(String key) { @@ -30,12 +30,12 @@ class ConstantMap implements Map { _keys.forEach((String key) => f(key, this[key])); } - Collection get keys => _keys; + Iterable get keys { + return new _ConstantMapKeyIterable(this); + } - Collection get values { - List result = []; - _keys.forEach((String key) => result.add(this[key])); - return result; + Iterable get values { + return new MappedIterable(_keys, (String key) => this[key]); } bool get isEmpty => length == 0; @@ -66,3 +66,10 @@ class ConstantProtoMap extends ConstantMap { return super[key]; } } + +class _ConstantMapKeyIterable extends Iterable { + ConstantMap _map; + _ConstantMapKeyIterable(this._map); + + Iterator get iterator => _map._keys.iterator; +} diff --git a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart index b375a97708a..ac6207870a3 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart @@ -75,11 +75,17 @@ patch class Expando { } patch class int { - patch static int parse(String source) => Primitives.parseInt(source); + patch static int parse(String source, + { int radix, + int onError(String source) }) { + return Primitives.parseInt(source, radix, onError); + } } patch class double { - patch static double parse(String source) => Primitives.parseDouble(source); + patch static double parse(String source, [int handleError(String source)]) { + return Primitives.parseDouble(source, handleError); + } } patch class Error { @@ -155,7 +161,44 @@ patch class _StopwatchImpl { // Patch for List implementation. patch class List { - patch factory List([int length]) => Primitives.newList(length); + patch factory List([int length = 0]) { + if ((length is !int) || (length < 0)) { + String lengthString = Error.safeToString(length); + throw new ArgumentError( + "Length must be a positive integer: $lengthString."); + } + return Primitives.newGrowableList(length); + } + + patch factory List.fixedLength(int length, {E fill: null}) { + if ((length is !int) || (length < 0)) { + throw new ArgumentError("Length must be a positive integer: $length."); + } + List result = Primitives.newFixedList(length); + if (length != 0 && fill != null) { + for (int i = 0; i < result.length; i++) { + result[i] = fill; + } + } + return result; + } + + /** + * Creates an extendable list of the given [length] where each entry is + * filled with [fill]. + */ + patch factory List.filled(int length, E fill) { + if ((length is !int) || (length < 0)) { + throw new ArgumentError("Length must be a positive integer: $length."); + } + List result = Primitives.newGrowableList(length); + if (length != 0 && fill != null) { + for (int i = 0; i < result.length; i++) { + result[i] = fill; + } + } + return result; + } } @@ -171,45 +214,38 @@ patch class String { // Patch for String implementation. patch class Strings { - patch static String join(List strings, String separator) { + patch static String join(Iterable strings, String separator) { checkNull(strings); if (separator is !String) throw new ArgumentError(separator); return stringJoinUnchecked(_toJsStringArray(strings), separator); } - patch static String concatAll(List strings) { + patch static String concatAll(Iterable strings) { return stringJoinUnchecked(_toJsStringArray(strings), ""); } - static List _toJsStringArray(List strings) { + static List _toJsStringArray(Iterable strings) { checkNull(strings); var array; - final length = strings.length; - if (isJsArray(strings)) { - array = strings; - for (int i = 0; i < length; i++) { - final string = strings[i]; - if (string is !String) throw new ArgumentError(string); - } - } else { - array = new List(length); - for (int i = 0; i < length; i++) { - final string = strings[i]; - if (string is !String) throw new ArgumentError(string); - array[i] = string; - } + if (!isJsArray(strings)) { + strings = new List.from(strings); } - return array; + final length = strings.length; + for (int i = 0; i < length; i++) { + final string = strings[i]; + if (string is !String) throw new ArgumentError(string); + } + return strings; } } patch class RegExp { patch factory RegExp(String pattern, {bool multiLine: false, - bool ignoreCase: false}) + bool caseSensitive: true}) => new JSSyntaxRegExp(pattern, multiLine: multiLine, - ignoreCase: ignoreCase); + caseSensitive: caseSensitive); } // Patch for 'identical' function. diff --git a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart index 6710c023685..4fd166d5c73 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart @@ -211,4 +211,4 @@ patch class _WindowsCodePageEncoder { patch static List _encodeString(String string) { throw new UnsupportedError("_WindowsCodePageEncoder._encodeString"); } -} \ No newline at end of file +} diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart index 21f71d1c9f8..08a2cbbe6c1 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart @@ -4,6 +4,7 @@ library _isolate_helper; +import 'dart:async'; import 'dart:isolate'; /** diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart index cd661b177c6..a948a8311e4 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart @@ -27,23 +27,3 @@ patch class ReceivePort { return new ReceivePortImpl(); } } - -patch class Timer { - patch factory Timer(int milliseconds, void callback(Timer timer)) { - if (!hasTimer()) { - throw new UnsupportedError("Timer interface not supported."); - } - return new TimerImpl(milliseconds, callback); - } - - /** - * Creates a new repeating timer. The [callback] is invoked every - * [milliseconds] millisecond until cancelled. - */ - patch factory Timer.repeating(int milliseconds, void callback(Timer timer)) { - if (!hasTimer()) { - throw new UnsupportedError("Timer interface not supported."); - } - return new TimerImpl.repeating(milliseconds, callback); - } -} diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart index c9987754645..01ebc02efd4 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart @@ -33,8 +33,8 @@ class JSArray implements List { return JS('var', r'#.pop()', this); } - List filter(bool f(E element)) { - return Collections.filter(this, [], f); + Iterable where(bool f(E element)) { + return new WhereIterable(this, f); } void addAll(Collection collection) { @@ -56,14 +56,55 @@ class JSArray implements List { return Collections.forEach(this, f); } - Collection map(f(E element)) { - return Collections.map(this, [], f); + List mappedBy(f(E element)) { + return new MappedList(this, f); + } + + String join([String separator]) { + if (separator == null) separator = ""; + var list = new List(this.length); + for (int i = 0; i < this.length; i++) { + list[i] = "${this[i]}"; + } + return JS('String', "#.join(#)", list, separator); + } + + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(E value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(E value)) { + return new SkipWhileIterable(this, test); } reduce(initialValue, combine(previousValue, E element)) { return Collections.reduce(this, initialValue, combine); } + E firstMatching(bool test(E value), {E orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + E lastMatching(bool test(E value), {E orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + E singleMatching(bool test(E value)) { + return Collections.singleMatching(this, test); + } + + E elementAt(int index) { + return this[index]; + } + List getRange(int start, int length) { // TODO(ngeoffray): Parameterize the return value. if (0 == length) return []; @@ -85,9 +126,25 @@ class JSArray implements List { return listInsertRange(this, start, length, initialValue); } - E get last => this[length - 1]; + E get first { + if (length > 0) return this[0]; + throw new StateError("No elements"); + } - E get first => this[0]; + E get last { + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); + } + + E get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + E min([int compare(E a, E b)]) => Collections.min(this, compare); + + E max([int compare(E a, E b)]) => Collections.max(this, compare); void removeRange(int start, int length) { checkGrowable(this, 'removeRange'); @@ -133,7 +190,7 @@ class JSArray implements List { Arrays.copy(from, startFrom, this, start, length); } - bool some(bool f(E element)) => Collections.some(this, f); + bool any(bool f(E element)) => Collections.any(this, f); bool every(bool f(E element)) => Collections.every(this, f); @@ -164,7 +221,11 @@ class JSArray implements List { String toString() => Collections.collectionToString(this); - ListIterator iterator() => new ListIterator(this); + List toList() => new List.from(this); + + Set toSet() => new Set.from(this); + + _ArrayIterator get iterator => new _ArrayIterator(this); int get hashCode => Primitives.objectHashCode(this); @@ -188,3 +249,27 @@ class JSArray implements List { return JS('var', '#[#]', this, index); } } + +/** Iterator for JavaScript Arrays. */ +class _ArrayIterator implements Iterator { + final List _list; + int _position; + T _current; + + _ArrayIterator(List this._list) : _position = -1; + + T get current => _current; + + bool moveNext() { + int nextPosition = _position + 1; + int length = _list.length; + if (nextPosition < length) { + _position = nextPosition; + _current = _list[nextPosition]; + return true; + } + _position = length; + _current = null; + return false; + } +} diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart index 39e1c5c8f65..fb7d66d8479 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart @@ -339,19 +339,6 @@ String S(value) { return res; } -class ListIterator implements Iterator { - int i; - List list; - ListIterator(List this.list) : i = 0; - bool get hasNext => i < JS('int', r'#.length', list); - T next() { - if (!hasNext) throw new StateError("No more elements"); - var value = JS('', r'#[#]', list, i); - i += 1; - return value; - } -} - createInvocationMirror(name, internalName, type, arguments, argumentNames) => new JSInvocationMirror(name, internalName, type, arguments, argumentNames); @@ -461,37 +448,97 @@ class Primitives { JS('void', "throw 'Unable to print message: ' + String(#)", string); } - static int parseInt(String string) { - checkString(string); - var match = JS('=List|Null', - r'/^\s*[+-]?(?:0(x)[a-f0-9]+|\d+)\s*$/i.exec(#)', - string); - if (match == null) { - throw new FormatException(string); - } - var base = 10; - if (match[1] != null) base = 16; - var result = JS('num', r'parseInt(#, #)', string, base); - if (result.isNaN) throw new FormatException(string); - return result; + static void _throwFormatException(String string) { + throw new FormatException(string); } - static double parseDouble(String string) { - checkString(string); + static int parseInt(String source, + int radix, + int handleError(String source)) { + if (handleError == null) handleError = _throwFormatException; + + checkString(source); + var match = JS('=List|Null', + r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(#)', + source); + int digitsIndex = 1; + int hexIndex = 2; + int decimalIndex = 3; + int nonDecimalHexIndex = 4; + if (radix == null) { + radix = 10; + if (match != null) { + if (match[hexIndex] != null) { + // Cannot fail because we know that the digits are all hex. + return JS('num', r'parseInt(#, 16)', source); + } + if (match[decimalIndex] != null) { + // Cannot fail because we know that the digits are all decimal. + return JS('num', r'parseInt(#, 10)', source); + } + return handleError(source); + } + } else { + if (radix is! int) throw new ArgumentError("Radix is not an integer"); + if (radix < 2 || radix > 36) { + throw new RangeError("Radix $radix not in range 2..36"); + } + if (match != null) { + if (radix == 10 && match[decimalIndex] != null) { + // Cannot fail because we know that the digits are all decimal. + return JS('num', r'parseInt(#, 10)', source); + } + if (radix < 10 || match[decimalIndex] == null) { + // We know that the characters must be ASCII as otherwise the + // regexp wouldn't have matched. Calling toLowerCase is thus + // guaranteed to be a safe operation. If it wasn't ASCII, then + // "İ" would become "i", and we would accept it for radices greater + // than 18. + int maxCharCode; + if (radix <= 10) { + // Allow all digits less than the radix. For example 0, 1, 2 for + // radix 3. + // "0".charCodeAt(0) + radix - 1; + maxCharCode = 0x30 + radix - 1; + } else { + // Characters are located after the digits in ASCII. Therefore we + // only check for the character code. The regexp above made already + // sure that the string does not contain anything but digits or + // characters. + // "0".charCodeAt(0) + radix - 1; + maxCharCode = 0x61 + radix - 10 - 1; + } + String digitsPart = match[digitsIndex].toLowerCase(); + for (int i = 0; i < digitsPart.length; i++) { + if (digitsPart.charCodeAt(i) > maxCharCode) { + return handleError(source); + } + } + } + } + } + if (match == null) return handleError(source); + return JS('num', r'parseInt(#, #)', source, radix); + } + + static double parseDouble(String source, int handleError(String source)) { + checkString(source); + if (handleError == null) handleError = _throwFormatException; // Notice that JS parseFloat accepts garbage at the end of the string. - // Accept, ignoring leading and trailing whitespace: + // Accept only: // - NaN // - [+/-]Infinity - // - a Dart double literal + // - a Dart double literal + // We do not allow leading or trailing whitespace. if (!JS('bool', r'/^\s*(?:NaN|[+-]?(?:Infinity|' r'(?:\.\d+|\d+(?:\.\d+)?)(?:[eE][+-]?\d+)?))\s*$/.test(#)', - string)) { - throw new FormatException(string); + source)) { + return handleError(source); } - var result = JS('num', r'parseFloat(#)', string); - if (result.isNaN && string != 'NaN') { - throw new FormatException(string); + var result = JS('num', r'parseFloat(#)', source); + if (result.isNaN && source != 'NaN') { + return handleError(source); } return result; } @@ -520,14 +567,17 @@ class Primitives { return "Instance of '$name'"; } - static List newList(length) { + static List newGrowableList(length) { + // TODO(sra): For good concrete type analysis we need the JS-type to + // specifically name the JavaScript Array implementation. 'List' matches + // all the dart:html types that implement List. + return JS('Object', r'new Array(#)', length); + } + + static List newFixedList(length) { // TODO(sra): For good concrete type analysis we need the JS-type to // specifically name the JavaScript Array implementation. 'List' matches // all the dart:html types that implement List. - if (length == null) return JS('=List', r'new Array()'); - if ((length is !int) || (length < 0)) { - throw new ArgumentError(length); - } var result = JS('=List', r'new Array(#)', length); JS('void', r'#.fixed$length = #', result, true); return result; @@ -855,37 +905,6 @@ checkString(value) { } class MathNatives { - static int parseInt(str) { - checkString(str); - if (!JS('bool', - r'/^\s*[+-]?(?:0[xX][abcdefABCDEF0-9]+|\d+)\s*$/.test(#)', - str)) { - throw new FormatException(str); - } - var trimmed = str.trim(); - var base = 10;; - if ((trimmed.length > 2 && (trimmed[1] == 'x' || trimmed[1] == 'X')) || - (trimmed.length > 3 && (trimmed[2] == 'x' || trimmed[2] == 'X'))) { - base = 16; - } - var ret = JS('num', r'parseInt(#, #)', trimmed, base); - if (ret.isNaN) throw new FormatException(str); - return ret; - } - - static double parseDouble(String str) { - checkString(str); - var ret = JS('num', r'parseFloat(#)', str); - if (ret == 0 && (str.startsWith("0x") || str.startsWith("0X"))) { - // TODO(ahe): This is unspecified, but tested by co19. - ret = JS('num', r'parseInt(#)', str); - } - if (ret.isNaN && str != 'NaN' && str != '-NaN') { - throw new FormatException(str); - } - return ret; - } - static double sqrt(num value) => JS('double', r'Math.sqrt(#)', checkNum(value)); @@ -1084,11 +1103,12 @@ class StackTrace { * a list of key, value, key, value, ..., etc. */ makeLiteralMap(List keyValuePairs) { - Iterator iterator = keyValuePairs.iterator(); + Iterator iterator = keyValuePairs.iterator; Map result = new LinkedHashMap(); - while (iterator.hasNext) { - String key = iterator.next(); - var value = iterator.next(); + while (iterator.moveNext()) { + String key = iterator.current; + iterator.moveNext(); + var value = iterator.current; result[key] = value; } return result; diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart index e8e57508c6e..c9f9dbfab2f 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart @@ -50,8 +50,8 @@ class JSNumber { num abs() => JS('num', r'Math.abs(#)', this); int toInt() { - if (isNaN) throw new FormatException('NaN'); - if (isInfinite) throw new FormatException('Infinity'); + if (isNaN) throw new UnsupportedError('NaN'); + if (isInfinite) throw new UnsupportedError('Infinity'); num truncated = truncate(); return JS('bool', r'# == -0.0', truncated) ? 0 : truncated; } @@ -73,21 +73,40 @@ class JSNumber { } } + num clamp(lowerLimit, upperLimit) { + if (lowerLimit is! num) throw new ArgumentError(lowerLimit); + if (upperLimit is! num) throw new ArgumentError(upperLimit); + if (lowerLimit.compareTo(upperLimit) > 0) { + throw new ArgumentError(lowerLimit); + } + if (this.compareTo(lowerLimit) < 0) return lowerLimit; + if (this.compareTo(upperLimit) > 0) return upperLimit; + return this; + } + double toDouble() => this; num truncate() => this < 0 ? ceil() : floor(); String toStringAsFixed(int fractionDigits) { checkNum(fractionDigits); + // TODO(floitsch): fractionDigits must be an integer. + if (fractionDigits < 0 || fractionDigits > 20) { + throw new RangeError(fractionDigits); + } String result = JS('String', r'#.toFixed(#)', this, fractionDigits); if (this == 0 && isNegative) return "-$result"; return result; } - String toStringAsExponential(int fractionDigits) { + String toStringAsExponential([int fractionDigits]) { String result; if (fractionDigits != null) { + // TODO(floitsch): fractionDigits must be an integer. checkNum(fractionDigits); + if (fractionDigits < 0 || fractionDigits > 20) { + throw new RangeError(fractionDigits); + } result = JS('String', r'#.toExponential(#)', this, fractionDigits); } else { result = JS('String', r'#.toExponential()', this); @@ -96,17 +115,21 @@ class JSNumber { return result; } - String toStringAsPrecision(int fractionDigits) { - checkNum(fractionDigits); + String toStringAsPrecision(int precision) { + // TODO(floitsch): precision must be an integer. + checkNum(precision); + if (precision < 1 || precision > 21) { + throw new RangeError(precision); + } String result = JS('String', r'#.toPrecision(#)', - this, fractionDigits); + this, precision); if (this == 0 && isNegative) return "-$result"; return result; } String toRadixString(int radix) { checkNum(radix); - if (radix < 2 || radix > 36) throw new ArgumentError(radix); + if (radix < 2 || radix > 36) throw new RangeError(radix); return JS('String', r'#.toString(#)', this, radix); } diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart index 3b5619819ce..5210b87ef67 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart @@ -42,6 +42,16 @@ class JSString implements String { return stringReplaceAllUnchecked(this, from, to); } + String replaceAllMapped(Pattern from, String convert(Match match)) { + return this.splitMapJoin(from, onMatch: convert); + } + + String splitMapJoin(Pattern from, + {String onMatch(Match match), + String onNonMatch(String nonMatch)}) { + return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch); + } + String replaceFirst(Pattern from, String to) { checkString(to); return stringReplaceFirstUnchecked(this, from, to); @@ -81,6 +91,42 @@ class JSString implements String { return JS('String', r'#.substring(#, #)', this, startIndex, endIndex); } + String slice([int startIndex, int endIndex]) { + int start, end; + if (startIndex == null) { + start = 0; + } else if (startIndex is! int) { + throw new ArgumentError("startIndex is not int"); + } else if (startIndex >= 0) { + start = startIndex; + } else { + start = this.length + startIndex; + } + if (start < 0 || start > this.length) { + throw new RangeError( + "startIndex out of range: $startIndex (length: $length)"); + } + if (endIndex == null) { + end = this.length; + } else if (endIndex is! int) { + throw new ArgumentError("endIndex is not int"); + } else if (endIndex >= 0) { + end = endIndex; + } else { + end = this.length + endIndex; + } + if (end < 0 || end > this.length) { + throw new RangeError( + "endIndex out of range: $endIndex (length: $length)"); + } + if (end < start) { + throw new ArgumentError( + "End before start: $endIndex < $startIndex (length: $length)"); + } + return JS('String', '#.substring(#, #)', this, start, end); + } + + String toLowerCase() { return JS('String', r'#.toLowerCase()', this); } @@ -94,7 +140,7 @@ class JSString implements String { } List get charCodes { - List result = new List(length); + List result = new List.fixedLength(length); for (int i = 0; i < length; i++) { result[i] = JS('int', '#.charCodeAt(#)', this, i); } diff --git a/sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart index 336664e712c..b62b0b5c5b4 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart @@ -30,12 +30,12 @@ regExpAttachGlobalNative(JSSyntaxRegExp regExp) { regExpMakeNative(JSSyntaxRegExp regExp, {bool global: false}) { String pattern = regExp.pattern; - bool multiLine = regExp.multiLine; - bool ignoreCase = regExp.ignoreCase; + bool isMultiLine = regExp.isMultiLine; + bool isCaseSensitive = regExp.isCaseSensitive; checkString(pattern); StringBuffer sb = new StringBuffer(); - if (multiLine) sb.add('m'); - if (ignoreCase) sb.add('i'); + if (isMultiLine) sb.add('m'); + if (!isCaseSensitive) sb.add('i'); if (global) sb.add('g'); try { return JS('var', r'new RegExp(#, #)', pattern, sb.toString()); @@ -49,15 +49,15 @@ int regExpMatchStart(m) => JS('int', r'#.index', m); class JSSyntaxRegExp implements RegExp { final String _pattern; - final bool _multiLine; - final bool _ignoreCase; + final bool _isMultiLine; + final bool _isCaseSensitive; const JSSyntaxRegExp(String pattern, {bool multiLine: false, - bool ignoreCase: false}) + bool caseSensitive: true}) : _pattern = pattern, - _multiLine = multiLine, - _ignoreCase = ignoreCase; + _isMultiLine = multiLine, + _isCaseSensitive = caseSensitive; Match firstMatch(String str) { List m = regExpExec(this, checkString(str)); @@ -81,13 +81,14 @@ class JSSyntaxRegExp implements RegExp { } String get pattern => _pattern; - bool get multiLine => _multiLine; - bool get ignoreCase => _ignoreCase; + bool get isMultiLine => _isMultiLine; + bool get isCaseSensitive => _isCaseSensitive; static JSSyntaxRegExp _globalVersionOf(JSSyntaxRegExp other) { - JSSyntaxRegExp re = new JSSyntaxRegExp(other.pattern, - multiLine: other.multiLine, - ignoreCase: other.ignoreCase); + JSSyntaxRegExp re = + new JSSyntaxRegExp(other.pattern, + multiLine: other.isMultiLine, + caseSensitive: other.isCaseSensitive); regExpAttachGlobalNative(re); return re; } @@ -122,50 +123,29 @@ class _MatchImplementation implements Match { } } -class _AllMatchesIterable implements Iterable { +class _AllMatchesIterable extends Iterable { final JSSyntaxRegExp _re; final String _str; const _AllMatchesIterable(this._re, this._str); - Iterator iterator() => new _AllMatchesIterator(_re, _str); + Iterator get iterator => new _AllMatchesIterator(_re, _str); } class _AllMatchesIterator implements Iterator { final RegExp _re; final String _str; - Match _next; - bool _done; + Match _current; _AllMatchesIterator(JSSyntaxRegExp re, String this._str) - : _done = false, _re = JSSyntaxRegExp._globalVersionOf(re); + : _re = JSSyntaxRegExp._globalVersionOf(re); - Match next() { - if (!hasNext) { - throw new StateError("No more elements"); - } - - // _next is set by [hasNext]. - var next = _next; - _next = null; - return next; - } - - bool get hasNext { - if (_done) { - return false; - } else if (_next != null) { - return true; - } + Match get current => _current; + bool moveNext() { // firstMatch actually acts as nextMatch because of // hidden global flag. - _next = _re.firstMatch(_str); - if (_next == null) { - _done = true; - return false; - } else { - return true; - } + _current = _re.firstMatch(_str); + return _current != null; } } diff --git a/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart index 8c363825c2f..6e4dccfb2b0 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart @@ -35,7 +35,7 @@ class StringMatch implements Match { List allMatchesInStringUnchecked(String needle, String haystack) { // Copied from StringBase.allMatches in - // ../../../runtime/lib/string.dart + // /runtime/lib/string_base.dart List result = new List(); int length = haystack.length; int patternLength = needle.length; @@ -65,7 +65,7 @@ stringContainsUnchecked(receiver, other, startIndex) { return other.hasMatch(receiver.substring(startIndex)); } else { var substr = receiver.substring(startIndex); - return other.allMatches(substr).iterator().hasNext; + return other.allMatches(substr).iterator.moveNext(); } } @@ -80,6 +80,7 @@ stringReplaceJS(receiver, replacer, to) { final RegExp quoteRegExp = new JSSyntaxRegExp(r'[-[\]{}()*+?.,\\^$|#\s]'); stringReplaceAllUnchecked(receiver, from, to) { + checkString(to); if (from is String) { if (from == "") { if (receiver == "") { @@ -111,6 +112,80 @@ stringReplaceAllUnchecked(receiver, from, to) { } } +String _matchString(Match match) => match[0]; +String _stringIdentity(String string) => string; + +stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { + if (pattern is! Pattern) { + throw new ArgumentError("${pattern} is not a Pattern"); + } + if (onMatch == null) onMatch = _matchString; + if (onNonMatch == null) onNonMatch = _stringIdentity; + if (pattern is String) { + return stringReplaceAllStringFuncUnchecked(receiver, pattern, + onMatch, onNonMatch); + } + StringBuffer buffer = new StringBuffer(); + int startIndex = 0; + for (Match match in pattern.allMatches(receiver)) { + buffer.add(onNonMatch(receiver.substring(startIndex, match.start))); + buffer.add(onMatch(match)); + startIndex = match.end; + } + buffer.add(onNonMatch(receiver.substring(startIndex))); + return buffer.toString(); +} + +stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) { + // Pattern is the empty string. + StringBuffer buffer = new StringBuffer(); + int length = receiver.length; + int i = 0; + buffer.add(onNonMatch("")); + while (i < length) { + buffer.add(onMatch(new StringMatch(i, receiver, ""))); + // Special case to avoid splitting a surrogate pair. + int code = receiver.charCodeAt(i); + if ((code & ~0x3FF) == 0xD800 && length > i + 1) { + // Leading surrogate; + code = receiver.charCodeAt(i + 1); + if ((code & ~0x3FF) == 0xDC00) { + // Matching trailing surrogate. + buffer.add(onNonMatch(receiver.substring(i, i + 2))); + i += 2; + continue; + } + } + buffer.add(onNonMatch(receiver[i])); + i++; + } + buffer.add(onMatch(new StringMatch(i, receiver, ""))); + buffer.add(onNonMatch("")); + return buffer.toString(); +} + +stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { + int patternLength = pattern.length; + if (patternLength == 0) { + return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch); + } + int length = receiver.length; + StringBuffer buffer = new StringBuffer(); + int startIndex = 0; + while (startIndex < length) { + int position = receiver.indexOf(pattern, startIndex); + if (position == -1) { + break; + } + buffer.add(onNonMatch(receiver.substring(startIndex, position))); + buffer.add(onMatch(new StringMatch(position, receiver, pattern))); + startIndex = position + patternLength; + } + buffer.add(onNonMatch(receiver.substring(startIndex))); + return buffer.toString(); +} + + stringReplaceFirstUnchecked(receiver, from, to) { if (from is String) { return stringReplaceJS(receiver, from, to); diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart index 3472b3eb267..f8befaf443c 100644 --- a/sdk/lib/_internal/compiler/implementation/library_loader.dart +++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart @@ -523,7 +523,7 @@ class LibraryDependencyNode { */ void registerInitialExports() { pendingExportSet.addAll( - library.localScope.values.filter((Element element) { + library.localScope.values.where((Element element) { // At this point [localScope] only contains members so we don't need // to check for foreign or prefix elements. return !element.name.isPrivate(); @@ -534,7 +534,7 @@ class LibraryDependencyNode { * Registers the compute export scope with the node library. */ void registerExports() { - library.setExports(exportScope.values); + library.setExports(exportScope.values.toList()); } /** diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart index acff12a5627..269410e23e3 100644 --- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart +++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart @@ -4,6 +4,7 @@ library mirrors_dart2js; +import 'dart:async'; import 'dart:io'; import 'dart:uri'; @@ -1304,14 +1305,15 @@ class Dart2JsInterfaceTypeMirror extends Dart2JsTypeElementMirror if (originalDeclaration != other.originalDeclaration) { return false; } - var thisTypeArguments = typeArguments.iterator(); - var otherTypeArguments = other.typeArguments.iterator(); - while (thisTypeArguments.hasNext && otherTypeArguments.hasNext) { - if (thisTypeArguments.next() != otherTypeArguments.next()) { + var thisTypeArguments = typeArguments.iterator; + var otherTypeArguments = other.typeArguments.iterator; + while (thisTypeArguments.moveNext()) { + if (!otherTypeArguments.moveNext()) return false; + if (thisTypeArguments.current != otherTypeArguments.current) { return false; } } - return !thisTypeArguments.hasNext && !otherTypeArguments.hasNext; + return !otherTypeArguments.moveNext(); } } @@ -1801,4 +1803,4 @@ class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror { } return super.getField(fieldName); } -} \ No newline at end of file +} diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart index 19e5cc09234..34bccc2f88f 100644 --- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart +++ b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart @@ -4,6 +4,7 @@ library mirrors; +import 'dart:async'; import 'dart:io'; import 'dart:uri'; @@ -194,9 +195,9 @@ abstract class InstanceMirror implements ObjectMirror { /** * Specialized [InstanceMirror] used for reflection on constant lists. */ -abstract class ListInstanceMirror - implements InstanceMirror, Sequence> { - +abstract class ListInstanceMirror implements InstanceMirror { + Future operator[](int index); + int get length; } /** @@ -717,4 +718,4 @@ class DartdocComment { final String text; const DartdocComment(this.text); -} \ No newline at end of file +} diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart index cede225be99..8614d9d6df1 100644 --- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart +++ b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart @@ -53,14 +53,14 @@ LibraryMirror findLibrary(MemberMirror member) { throw new Exception('Unexpected owner: ${owner}'); } -class HierarchyIterable implements Iterable { +class HierarchyIterable extends Iterable { final bool includeType; final ClassMirror type; HierarchyIterable(this.type, {bool includeType}) : this.includeType = includeType; - Iterator iterator() => + Iterator get iterator => new HierarchyIterator(type, includeType: includeType); } @@ -68,7 +68,7 @@ class HierarchyIterable implements Iterable { * [HierarchyIterator] iterates through the class hierarchy of the provided * type. * - * First is the superclass relation is traversed, skipping [Object], next the + * First the superclass relation is traversed, skipping [Object], next the * superinterface relation and finally is [Object] visited. The supertypes are * visited in breadth first order and a superinterface is visited more than once * if implemented through multiple supertypes. @@ -76,6 +76,7 @@ class HierarchyIterable implements Iterable { class HierarchyIterator implements Iterator { final Queue queue = new Queue(); ClassMirror object; + ClassMirror _current; HierarchyIterator(ClassMirror type, {bool includeType}) { if (includeType) { @@ -97,19 +98,18 @@ class HierarchyIterator implements Iterator { return type; } - ClassMirror next() { - ClassMirror type; + ClassMirror get current => _current; + + bool moveNext() { + _current = null; if (queue.isEmpty) { - if (object == null) { - throw new StateError("No more elements"); - } - type = object; + if (object == null) return false; + _current = object; object = null; - return type; + return true; } else { - return push(queue.removeFirst()); + _current = push(queue.removeFirst()); + return true; } } - - bool get hasNext => !queue.isEmpty || object != null; } diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart index 4367c6d9dde..c0af4bf09d0 100644 --- a/sdk/lib/_internal/compiler/implementation/native_handler.dart +++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart @@ -33,7 +33,7 @@ class SpecialType { */ class NativeEnqueuer { /// Initial entry point to native enqueuer. - void processNativeClasses(Collection libraries) {} + void processNativeClasses(Iterable libraries) {} /// Notification of a main Enqueuer worklist element. For methods, adds /// information from metadata attributes, and computes types instantiated due @@ -101,7 +101,7 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); - void processNativeClasses(Collection libraries) { + void processNativeClasses(Iterable libraries) { libraries.forEach(processNativeClassesInLibrary); processNativeClassesInLibrary(compiler.isolateHelperLibrary); if (!enableLiveTypeAnalysis) { @@ -350,7 +350,7 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { enqueueUnusedClassesMatching(bool predicate(classElement), cause, [String reason]) { - Collection matches = unusedClasses.filter(predicate); + Iterable matches = unusedClasses.where(predicate); matches.forEach((c) => enqueueClass(c, cause)); } @@ -400,7 +400,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase { NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) : super(world, compiler, compiler.enableNativeLiveTypeAnalysis); - void processNativeClasses(Collection libraries) { + void processNativeClasses(Iterable libraries) { super.processNativeClasses(libraries); // HACK HACK - add all the resolved classes. @@ -454,6 +454,7 @@ void maybeEnableNative(Compiler compiler, String libraryName = uri.toString(); if (library.entryCompilationUnit.script.name.contains( 'dart/tests/compiler/dart2js_native') + || libraryName == 'dart:async' || libraryName == 'dart:html' || libraryName == 'dart:html_common' || libraryName == 'dart:indexed_db' diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart index e9445056011..278e8009aef 100644 --- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart +++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart @@ -2359,10 +2359,10 @@ class ResolverVisitor extends CommonResolverVisitor { visitForIn(ForIn node) { for (final name in const [ const SourceString('iterator'), - const SourceString('next')]) { - registerImplicitInvocation(name, 0); + const SourceString('current')]) { + registerImplicitFieldGet(name); } - registerImplicitFieldGet(const SourceString('hasNext')); + registerImplicitInvocation(const SourceString('moveNext'), 0); visit(node.expression); Scope blockScope = new BlockScope(scope); Node declaration = node.declaredIdentifier; diff --git a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart index af5b0e768b5..92e7840bba0 100644 --- a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart +++ b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart @@ -104,13 +104,13 @@ class MethodScope extends MutableScope { MethodScope(Scope parent, this.element) : super(parent); - String toString() => 'MethodScope($element${elements.keys})'; + String toString() => 'MethodScope($element${elements.keys.toList()})'; } class BlockScope extends MutableScope { BlockScope(Scope parent) : super(parent); - String toString() => 'BlockScope(${elements.keys})'; + String toString() => 'BlockScope(${elements.keys.toList()})'; } /** diff --git a/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart b/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart index f6c220f4aa4..4d7989872f3 100644 --- a/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart +++ b/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart @@ -5,7 +5,7 @@ /** * An abstract string representation. */ -class ByteString implements SourceString { +abstract class ByteString extends Iterable implements SourceString { final List bytes; final int offset; final int length; @@ -24,7 +24,7 @@ class ByteString implements SourceString { throw "should be overridden in subclass"; } - Iterator iterator() => new Utf8Decoder(bytes, offset, length); + Iterator get iterator => new Utf8Decoder(bytes, offset, length); int get hashCode { if (_hashCode == null) { @@ -66,7 +66,7 @@ class AsciiString extends ByteString { return string; } - Iterator iterator() => new AsciiStringIterator(bytes); + Iterator get iterator => new AsciiStringIterator(bytes); SourceString copyWithoutQuotes(int initial, int terminal) { return new AsciiString(bytes, offset + initial, @@ -85,12 +85,22 @@ class AsciiStringIterator implements Iterator { final List bytes; int offset; final int end; + int _current; + AsciiStringIterator(List bytes) : this.bytes = bytes, offset = 0, end = bytes.length; AsciiStringIterator.range(List bytes, int from, int length) : this.bytes = bytes, offset = from, end = from + length; - bool get hasNext => offset < end; - int next() => bytes[offset++]; + + int get current => _current; + bool moveNext() { + if (offset < end) { + _current = bytes[offset++]; + return true; + } + _current = null; + return false; + } } @@ -111,7 +121,7 @@ class Utf8String extends ByteString { throw "not implemented yet"; } - Iterator iterator() => new Utf8Decoder(bytes, 0, length); + Iterator get iterator => new Utf8Decoder(bytes, 0, length); SourceString copyWithoutQuotes(int initial, int terminal) { assert((){ diff --git a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart index 4a23d73cc6d..3a6db1151f1 100644 --- a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart +++ b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart @@ -7,7 +7,7 @@ part of scanner; /** * A keyword in the Dart programming language. */ -class Keyword implements SourceString { +class Keyword extends Iterable implements SourceString { static const List values = const [ const Keyword("assert"), const Keyword("break"), @@ -102,7 +102,7 @@ class Keyword implements SourceString { return other is SourceString && toString() == other.slowToString(); } - Iterator iterator() => new StringCodeIterator(syntax); + Iterator get iterator => new StringCodeIterator(syntax); void printOn(StringBuffer sb) { sb.add(syntax); @@ -132,7 +132,8 @@ abstract class KeywordState { static KeywordState _KEYWORD_STATE; static KeywordState get KEYWORD_STATE { if (_KEYWORD_STATE == null) { - List strings = new List(Keyword.values.length); + List strings = + new List.fixedLength(Keyword.values.length); for (int i = 0; i < Keyword.values.length; i++) { strings[i] = Keyword.values[i].syntax; } @@ -144,7 +145,7 @@ abstract class KeywordState { static KeywordState computeKeywordStateTable(int start, List strings, int offset, int length) { - List result = new List(26); + List result = new List.fixedLength(26); assert(length != 0); int chunk = 0; int chunkStart = -1; diff --git a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart index 958db2f9fbf..0fa3489eee3 100644 --- a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart +++ b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart @@ -53,7 +53,7 @@ class StringScanner extends ArrayBasedScanner { } } -class SubstringWrapper implements SourceString { +class SubstringWrapper extends Iterable implements SourceString { final String internalString; final int begin; final int end; @@ -89,7 +89,7 @@ class SubstringWrapper implements SourceString { String get stringValue => null; - Iterator iterator() => + Iterator get iterator => new StringCodeIterator.substring(internalString, begin, end); SourceString copyWithoutQuotes(int initial, int terminal) { diff --git a/sdk/lib/_internal/compiler/implementation/scanner/token.dart b/sdk/lib/_internal/compiler/implementation/scanner/token.dart index 573fc4f8dbc..b80ca1503a5 100644 --- a/sdk/lib/_internal/compiler/implementation/scanner/token.dart +++ b/sdk/lib/_internal/compiler/implementation/scanner/token.dart @@ -205,7 +205,7 @@ abstract class SourceString extends Iterable { bool isPrivate(); } -class StringWrapper implements SourceString { +class StringWrapper extends Iterable implements SourceString { final String stringValue; const StringWrapper(String this.stringValue); @@ -216,7 +216,7 @@ class StringWrapper implements SourceString { return other is SourceString && toString() == other.slowToString(); } - Iterator iterator() => new StringCodeIterator(stringValue); + Iterator get iterator => new StringCodeIterator(stringValue); void printOn(StringBuffer sb) { sb.add(stringValue); @@ -243,6 +243,7 @@ class StringCodeIterator implements Iterator { final String string; int index; final int end; + int _current; StringCodeIterator(String string) : this.string = string, index = 0, end = string.length; @@ -253,8 +254,14 @@ class StringCodeIterator implements Iterator { assert(end <= string.length); } - bool get hasNext => index < end; - int next() => string.charCodeAt(index++); + int get current => _current; + + bool moveNext() { + _current = null; + if (index >= end) return false; + _current = string.charCodeAt(index++); + return true; + } } class BeginGroupToken extends StringToken { diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart index 277be1e64bb..ed776e7afcf 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart @@ -3973,9 +3973,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { visitForIn(ForIn node) { // Generate a structure equivalent to: - // Iterator $iter = .iterator() - // while ($iter.hasNext) { - // E = $iter.next(); + // Iterator $iter = .iterator; + // while ($iter.moveNext()) { + // E = $iter.current; // // } @@ -3984,32 +3984,38 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { void buildInitializer() { SourceString iteratorName = const SourceString("iterator"); Selector selector = - new Selector.call(iteratorName, work.element.getLibrary(), 0); + new Selector.getter(iteratorName, work.element.getLibrary()); Set interceptedClasses = interceptors.getInterceptedClassesOn(selector); visit(node.expression); HInstruction receiver = pop(); + bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); if (interceptedClasses == null) { - iterator = new HInvokeDynamicMethod(selector, [receiver]); + iterator = + new HInvokeDynamicGetter(selector, null, receiver, hasGetter); } else { HInterceptor interceptor = invokeInterceptor(interceptedClasses, receiver, null); - iterator = new HInvokeDynamicMethod( - selector, [interceptor, receiver]); + iterator = + new HInvokeDynamicGetter(selector, null, interceptor, hasGetter); + // Add the receiver as an argument to the getter call on the + // interceptor. + iterator.inputs.add(receiver); } add(iterator); } HInstruction buildCondition() { - SourceString name = const SourceString('hasNext'); - Selector selector = new Selector.getter(name, work.element.getLibrary()); + SourceString name = const SourceString('moveNext'); + Selector selector = new Selector.call(name, work.element.getLibrary(), 0); bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector); - push(new HInvokeDynamicGetter(selector, null, iterator, !hasGetter)); + push(new HInvokeDynamicMethod(selector, [iterator])); return popBoolified(); } void buildBody() { - SourceString name = const SourceString('next'); - Selector call = new Selector.call(name, work.element.getLibrary(), 0); - push(new HInvokeDynamicMethod(call, [iterator])); + SourceString name = const SourceString('current'); + Selector call = new Selector.getter(name, work.element.getLibrary()); + bool hasGetter = compiler.world.hasAnyUserDefinedGetter(call); + push(new HInvokeDynamicGetter(call, null, iterator, hasGetter)); Element variable; if (node.declaredIdentifier.asSend() != null) { @@ -4237,7 +4243,8 @@ class SsaBuilder extends ResolvedVisitor implements Visitor { bool hasDefault = false; Element getFallThroughErrorElement = compiler.findHelper(const SourceString("getFallThroughError")); - Iterator caseIterator = node.cases.iterator(); + HasNextIterator caseIterator = + new HasNextIterator(node.cases.iterator); while (caseIterator.hasNext) { SwitchCase switchCase = caseIterator.next(); List caseConstants = []; diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart index 6af28ded2a9..3d2dcf1226b 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart @@ -127,7 +127,11 @@ class OrderedSet { void forEach(f) => map.keys.forEach(f); - T get first => map.keys.iterator().next(); + T get first { + var iterator = map.keys.iterator; + if (!iterator.moveNext()) throw new StateError("No elements"); + return iterator.current; + } get length => map.length; } @@ -1143,7 +1147,7 @@ abstract class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { * Sequentialize a list of conceptually parallel copies. Parallel * copies may contain cycles, that this method breaks. */ - void sequentializeCopies(List copies, + void sequentializeCopies(Iterable copies, String tempName, void doAssignment(String target, String source)) { // Map to keep track of the current location (ie the variable that @@ -1226,7 +1230,7 @@ abstract class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { if (handler == null) return; // Map the instructions to strings. - List copies = handler.copies.map((Copy copy) { + Iterable copies = handler.copies.mappedBy((Copy copy) { return new Copy(variableNames.getName(copy.source), variableNames.getName(copy.destination)); }); diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart index 23359cfb9e0..7153167c42b 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart @@ -270,9 +270,21 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { bool isFixedSizeListConstructor(HInvokeStatic node) { Element element = node.target.element; - return element.getEnclosingClass() == compiler.listClass - && node.inputs.length == 2 - && node.inputs[1].isInteger(types); + if (element.getEnclosingClass() != compiler.listClass) return false; + if (!element.isConstructor()) return false; + // Check that the constructor is called with an argument and that this + // argument is an integer. + // TODO(ngeoffray): maybe change the name of the function to reflect that + // we also look at the argument. + if (node.inputs.length != 2) return false; + if (!node.inputs[1].isInteger(types)) return false; + + // TODO(ngeoffray): cache constructor. + FunctionElement fixedLengthListConstructor = + compiler.listClass.lookupConstructor( + new Selector.callConstructor(const SourceString("fixedLength"), + compiler.listClass.getLibrary())); + return element == fixedLengthListConstructor.defaultImplementation; } HInstruction visitInvokeStatic(HInvokeStatic node) { @@ -608,7 +620,8 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { HInstruction visitFieldGet(HFieldGet node) { if (node.element == backend.jsArrayLength) { if (node.receiver is HInvokeStatic) { - // Try to recognize the length getter with input [:new List(int):]. + // Try to recognize the length getter with input + // [:new List.fixedLength(int):]. HInvokeStatic call = node.receiver; if (isFixedSizeListConstructor(call)) { return call.inputs[1]; @@ -1090,8 +1103,8 @@ class SsaGlobalValueNumberer implements OptimizationPhase { // loop changes flags list to zero so we can use bitwise or when // propagating loop changes upwards. final int length = graph.blocks.length; - blockChangesFlags = new List(length); - loopChangesFlags = new List(length); + blockChangesFlags = new List.fixedLength(length); + loopChangesFlags = new List.fixedLength(length); for (int i = 0; i < length; i++) loopChangesFlags[i] = 0; // Run through all the basic blocks in the graph and fill in the @@ -1167,7 +1180,7 @@ class SsaCodeMotion extends HBaseVisitor implements OptimizationPhase { List values; void visitGraph(HGraph graph) { - values = new List(graph.blocks.length); + values = new List.fixedLength(graph.blocks.length); for (int i = 0; i < graph.blocks.length; i++) { values[graph.blocks[i].id] = new ValueSet(); } diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart index b68e688763f..d565de77ebd 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart @@ -8,7 +8,7 @@ class ValueSet { int size = 0; List table; ValueSetNode collisions; - ValueSet() : table = new List(8); + ValueSet() : table = new List.fixedLength(8); bool get isEmpty => size == 0; int get length => size; @@ -137,7 +137,7 @@ class ValueSet { // Reset the table with a bigger capacity. assert(capacity > table.length); size = 0; - table = new List(capacity); + table = new List.fixedLength(capacity); collisions = null; // Add the old instructions to the new table. copyTo(this, oldTable, oldCollisions); diff --git a/sdk/lib/_internal/compiler/implementation/string_validator.dart b/sdk/lib/_internal/compiler/implementation/string_validator.dart index b3bcb616edc..076a0c20385 100644 --- a/sdk/lib/_internal/compiler/implementation/string_validator.dart +++ b/sdk/lib/_internal/compiler/implementation/string_validator.dart @@ -45,29 +45,31 @@ class StringValidator { } static StringQuoting quotingFromString(SourceString sourceString) { - Iterator source = sourceString.iterator(); + Iterator source = sourceString.iterator; bool raw = false; int quoteLength = 1; - int quoteChar = source.next(); - if (identical(quoteChar, $r)) { + source.moveNext(); + int quoteChar = source.current; + if (quoteChar == $r) { raw = true; - quoteChar = source.next(); + source.moveNext(); + quoteChar = source.current; } assert(quoteChar == $SQ || quoteChar == $DQ); // String has at least one quote. Check it if has three. // If it only have two, the string must be an empty string literal, // and end after the second quote. bool multiline = false; - if (source.hasNext && source.next() == quoteChar && source.hasNext) { - int code = source.next(); + if (source.moveNext() && source.current == quoteChar && source.moveNext()) { + int code = source.current; assert(code == quoteChar); // If not, there is a bug in the parser. quoteLength = 3; // Check if a multiline string starts with a newline (CR, LF or CR+LF). - if (source.hasNext) { - code = source.next(); + if (source.moveNext()) { + code = source.current; if (code == $CR) { quoteLength += 1; - if (source.hasNext && source.next() == $LF) { + if (source.moveNext() && source.current == $LF) { quoteLength += 1; } } else if (code == $LF) { @@ -99,7 +101,9 @@ class StringValidator { bool containsEscape = false; bool previousWasLeadSurrogate = false; bool invalidUtf16 = false; - for(Iterator iter = string.iterator(); iter.hasNext; length++) { + for(HasNextIterator iter = new HasNextIterator(string.iterator); + iter.hasNext; + length++) { index++; int code = iter.next(); if (code == $BACKSLASH) { @@ -130,14 +134,17 @@ class StringValidator { } else if (code == $u) { int escapeStart = index - 1; index++; - code = iter.next(); + code = iter.hasNext ? iter.next() : 0; int value = 0; if (code == $OPEN_CURLY_BRACKET) { // expect 1-6 hex digits. int count = 0; - index++; - code = iter.next(); - do { + while (iter.hasNext) { + code = iter.next(); + index++; + if (code == $CLOSE_CURLY_BRACKET) { + break; + } if (!isHexDigit(code)) { stringParseError("Invalid character in escape sequence", token, index); @@ -145,20 +152,24 @@ class StringValidator { } count++; value = value * 16 + hexDigitValue(code); - index++; - code = iter.next(); - } while (code != $CLOSE_CURLY_BRACKET); - if (count > 6) { + } + if (code != $CLOSE_CURLY_BRACKET || count == 0 || count > 6) { + int errorPosition = index - count; + if (count > 6) errorPosition += 6; stringParseError("Invalid character in escape sequence", - token, index - (count - 6)); + token, errorPosition); return null; } } else { // Expect four hex digits, including the one just read. for (int i = 0; i < 4; i++) { if (i > 0) { - index++; - code = iter.next(); + if (iter.hasNext) { + index++; + code = iter.next(); + } else { + code = 0; + } } if (!isHexDigit(code)) { stringParseError("Invalid character in escape sequence", diff --git a/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart b/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart index 08ed05ac679..5a3494d6e90 100644 --- a/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart +++ b/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart @@ -11,7 +11,7 @@ part of tree; * representing its content after removing quotes and resolving escapes in * its source. */ -abstract class DartString implements Iterable { +abstract class DartString extends Iterable { factory DartString.empty() => const LiteralDartString(""); // This is a convenience constructor. If you need a const literal DartString, // use [const LiteralDartString(string)] directly. @@ -28,17 +28,18 @@ abstract class DartString implements Iterable { const DartString(); int get length; bool get isEmpty => length == 0; - Iterator iterator(); + Iterator get iterator; String slowToString(); bool operator ==(var other) { if (other is !DartString) return false; DartString otherString = other; if (length != otherString.length) return false; - Iterator it1 = iterator(); - Iterator it2 = otherString.iterator(); - while (it1.hasNext) { - if (it1.next() != it2.next()) return false; + Iterator it1 = iterator; + Iterator it2 = otherString.iterator; + while (it1.moveNext()) { + if (!it2.moveNext()) return false; + if (it1.current != it2.current) return false; } return true; } @@ -54,7 +55,7 @@ class LiteralDartString extends DartString { final String string; const LiteralDartString(this.string); int get length => string.length; - Iterator iterator() => new StringCodeIterator(string); + Iterator get iterator => new StringCodeIterator(string); String slowToString() => string; SourceString get source => new StringWrapper(string); } @@ -67,7 +68,7 @@ abstract class SourceBasedDartString extends DartString { final SourceString source; final int length; SourceBasedDartString(this.source, this.length); - Iterator iterator(); + Iterator get iterator; } /** @@ -76,7 +77,7 @@ abstract class SourceBasedDartString extends DartString { */ class RawSourceDartString extends SourceBasedDartString { RawSourceDartString(source, length) : super(source, length); - Iterator iterator() => source.iterator(); + Iterator get iterator => source.iterator; String slowToString() { if (toStringCache != null) return toStringCache; toStringCache = source.slowToString(); @@ -90,7 +91,7 @@ class RawSourceDartString extends SourceBasedDartString { */ class EscapedSourceDartString extends SourceBasedDartString { EscapedSourceDartString(source, length) : super(source, length); - Iterator iterator() { + Iterator get iterator { if (toStringCache != null) return new StringCodeIterator(toStringCache); return new StringEscapeIterator(source); } @@ -98,8 +99,8 @@ class EscapedSourceDartString extends SourceBasedDartString { if (toStringCache != null) return toStringCache; StringBuffer buffer = new StringBuffer(); StringEscapeIterator it = new StringEscapeIterator(source); - while (it.hasNext) { - buffer.addCharCode(it.next()); + while (it.moveNext()) { + buffer.addCharCode(it.current); } toStringCache = buffer.toString(); return toStringCache; @@ -119,7 +120,7 @@ class ConsDartString extends DartString { this.right = right, length = left.length + right.length; - Iterator iterator() => new ConsDartStringIterator(this); + Iterator get iterator => new ConsDartStringIterator(this); String slowToString() { if (toStringCache != null) return toStringCache; @@ -130,34 +131,39 @@ class ConsDartString extends DartString { } class ConsDartStringIterator implements Iterator { - Iterator current; + HasNextIterator currentIterator; DartString right; bool hasNextLookAhead; + int _current = null; + ConsDartStringIterator(ConsDartString cons) - : current = cons.left.iterator(), + : currentIterator = new HasNextIterator(cons.left.iterator), right = cons.right { - hasNextLookAhead = current.hasNext; + hasNextLookAhead = currentIterator.hasNext; if (!hasNextLookAhead) { nextPart(); } } - bool get hasNext { - return hasNextLookAhead; - } - int next() { - assert(hasNextLookAhead); - int result = current.next(); - hasNextLookAhead = current.hasNext; + + int get current => _current; + + bool moveNext() { + if (!hasNextLookAhead) { + _current = null; + return false; + } + _current = currentIterator.next(); + hasNextLookAhead = currentIterator.hasNext; if (!hasNextLookAhead) { nextPart(); } - return result; + return true; } void nextPart() { if (right != null) { - current = right.iterator(); + currentIterator = new HasNextIterator(right.iterator); right = null; - hasNextLookAhead = current.hasNext; + hasNextLookAhead = currentIterator.hasNext; } } } @@ -167,45 +173,63 @@ class ConsDartStringIterator implements Iterator { */ class StringEscapeIterator implements Iterator{ final Iterator source; - StringEscapeIterator(SourceString source) : this.source = source.iterator(); - bool get hasNext => source.hasNext; - int next() { - int code = source.next(); - if (!identical(code, $BACKSLASH)) { - return code; + int _current = null; + + StringEscapeIterator(SourceString source) : this.source = source.iterator; + + int get current => _current; + + bool moveNext() { + if (!source.moveNext()) { + _current = null; + return false; } - code = source.next(); - if (identical(code, $n)) return $LF; - if (identical(code, $r)) return $CR; - if (identical(code, $t)) return $TAB; - if (identical(code, $b)) return $BS; - if (identical(code, $f)) return $FF; - if (identical(code, $v)) return $VTAB; - if (identical(code, $x)) { - int value = hexDigitValue(source.next()); - value = value * 16 + hexDigitValue(source.next()); - return value; + int code = source.current; + if (code != $BACKSLASH) { + _current = code; + return true; } - if (identical(code, $u)) { - int value = 0; - code = source.next(); - if (identical(code, $OPEN_CURLY_BRACKET)) { - for (code = source.next(); - code != $CLOSE_CURLY_BRACKET; - code = source.next()) { - value = value * 16 + hexDigitValue(code); + source.moveNext(); + code = source.current; + switch (code) { + case $n: _current = $LF; break; + case $r: _current = $CR; break; + case $t: _current = $TAB; break; + case $b: _current = $BS; break; + case $f: _current = $FF; break; + case $v: _current = $VTAB; break; + case $x: + source.moveNext(); + int value = hexDigitValue(source.current); + source.moveNext(); + value = value * 16 + hexDigitValue(source.current); + _current = value; + break; + case $u: + int value = 0; + source.moveNext(); + code = source.current; + if (code == $OPEN_CURLY_BRACKET) { + source.moveNext(); + while (source.current != $CLOSE_CURLY_BRACKET) { + value = value * 16 + hexDigitValue(source.current); + source.moveNext(); + } + _current = value; + break; } - return value; - } - // Four digit hex value. - value = hexDigitValue(code); - for (int i = 0; i < 3; i++) { - code = source.next(); - value = value * 16 + hexDigitValue(code); - } - return value; + // Four digit hex value. + value = hexDigitValue(code); + for (int i = 0; i < 3; i++) { + source.moveNext(); + value = value * 16 + hexDigitValue(source.current); + } + _current = value; + break; + default: + _current = code; } - return code; + return true; } } diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart index 8f463f828bf..8099a56c430 100644 --- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart +++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart @@ -288,7 +288,7 @@ class Send extends Expression { if (argumentsNode != null) argumentsNode.accept(visitor); } - int argumentCount() => (argumentsNode == null) ? -1 : argumentsNode.length(); + int argumentCount() => (argumentsNode == null) ? -1 : argumentsNode.length; bool get isSuperCall { return receiver != null && @@ -419,14 +419,14 @@ class NodeList extends Node implements Iterable { NodeList([this.beginToken, this.nodes, this.endToken, this.delimiter]); - Iterator iterator() => nodes.iterator(); + Iterator get iterator => nodes.iterator; NodeList.singleton(Node node) : this(null, const Link().prepend(node)); NodeList.empty() : this(null, const Link()); NodeList asNodeList() => this; - int length() { + int get length { int result = 0; for (Link cursor = nodes; !cursor.isEmpty; cursor = cursor.tail) { result++; @@ -469,6 +469,97 @@ class NodeList extends Node implements Iterable { } return beginToken; } + + // ------------------- Iterable methods ------------------------------------- + // + // TODO(floitsch): these functions should be pulled in through a mixin + // mechanism. + Iterable mappedBy(f(Node element)) => new MappedIterable(this, f); + + Iterable where(bool f(Node element)) + => new WhereIterable(this, f); + + bool contains(Node element) { + for (Node e in this) { + if (e == element) return true; + } + return false; + } + + void forEach(void f(Node element)) { + for (Node element in this) f(element); + } + + String join([String separator]) => Collections.join(this, separator); + + dynamic reduce(var initialValue, + dynamic combine(var previousValue, Node element)) { + var value = initialValue; + for (Node element in this) value = combine(value, element); + return value; + } + + bool every(bool f(Node element)) { + for (Node element in this) { + if (!f(element)) return false; + } + return true; + } + + bool any(bool f(Node element)) { + for (Node element in this) { + if (f(element)) return true; + } + return false; + } + + List toList() => new List.from(this); + + Set toSet() => new Set.from(this); + + Iterable take(int n) => new TakeIterable(this, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + Iterable skip(int n) => new SkipIterable(this, n); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node get first { + return Collections.first(this); + } + + Node get last { + return Collections.last(this); + } + + Node get single { + return Collections.single(this); + } + + Node min([int compare(Node a, Node b)]) => Collections.min(this, compare); + + Node max([int compare(Node a, Node b)]) => Collections.max(this, compare); + + Node firstMatching(bool test(Node value), {Node orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatching(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return Collections.elementAt(this, index); + } } class Block extends Statement { @@ -686,7 +777,7 @@ class LiteralInt extends Literal { try { Token valueToken = token; if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; - return parseInt(valueToken.value.slowToString()); + return int.parse(valueToken.value.slowToString()); } on FormatException catch (ex) { (this.handler)(token, ex); } @@ -705,7 +796,7 @@ class LiteralDouble extends Literal { try { Token valueToken = token; if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; - return parseDouble(valueToken.value.slowToString()); + return double.parse(valueToken.value.slowToString()); } on FormatException catch (ex) { (this.handler)(token, ex); } diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart index 1f410c1657f..3b60b533d64 100644 --- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart +++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart @@ -139,7 +139,7 @@ class Unparser implements Visitor { visitFunctionExpression(FunctionExpression node) { // Check length to not print unnecessary whitespace. - if (node.modifiers.nodes.length() > 0) { + if (node.modifiers.nodes.length > 0) { visit(node.modifiers); sb.add(' '); } @@ -334,7 +334,7 @@ class Unparser implements Visitor { visitVariableDefinitions(VariableDefinitions node) { visit(node.modifiers); - if (node.modifiers.nodes.length() > 0) { + if (node.modifiers.nodes.length > 0) { sb.add(' '); } if (node.type != null) { diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart index e33d173ccb9..eb5f364188e 100644 --- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart +++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart @@ -171,7 +171,9 @@ class UnionType implements ConcreteType { ClassElement getUniqueType() { if (baseTypes.length == 1) { - BaseType uniqueBaseType = baseTypes.iterator().next(); + var iterator = baseTypes.iterator; + iterator.moveNext(); + BaseType uniqueBaseType = iterator.current; if (uniqueBaseType.isClass()) { ClassBaseType uniqueClassType = uniqueBaseType; return uniqueClassType.element; @@ -190,14 +192,14 @@ class UnionType implements ConcreteType { * [: (A, D) :], [: (B, C) :] and finally [: (B, D) :]. */ class ConcreteTypeCartesianProduct - implements Iterable { + extends Iterable { final ConcreteTypesInferrer inferrer; final BaseType baseTypeOfThis; final Map concreteTypes; ConcreteTypeCartesianProduct(this.inferrer, this.baseTypeOfThis, this.concreteTypes); - Iterator iterator() => concreteTypes.isEmpty - ? [new ConcreteTypesEnvironment(inferrer, baseTypeOfThis)].iterator() + Iterator get iterator => concreteTypes.isEmpty + ? [new ConcreteTypesEnvironment(inferrer, baseTypeOfThis)].iterator : new ConcreteTypeCartesianProductIterator(inferrer, baseTypeOfThis, concreteTypes); String toString() { @@ -210,7 +212,8 @@ class ConcreteTypeCartesianProduct /** * An helper class for [ConcreteTypeCartesianProduct]. */ -class ConcreteTypeCartesianProductIterator implements Iterator { +class ConcreteTypeCartesianProductIterator + implements Iterator { final ConcreteTypesInferrer inferrer; final BaseType baseTypeOfThis; final Map concreteTypes; @@ -218,6 +221,7 @@ class ConcreteTypeCartesianProductIterator implements Iterator { final Map state; int size = 1; int counter = 0; + ConcreteTypesEnvironment _current; ConcreteTypeCartesianProductIterator(this.inferrer, this.baseTypeOfThis, Map concreteTypes) @@ -234,9 +238,7 @@ class ConcreteTypeCartesianProductIterator implements Iterator { } } - bool get hasNext { - return counter < size; - } + ConcreteTypesEnvironment get current => _current; ConcreteTypesEnvironment takeSnapshot() { Map result = new Map(); @@ -246,21 +248,26 @@ class ConcreteTypeCartesianProductIterator implements Iterator { return new ConcreteTypesEnvironment.of(inferrer, result, baseTypeOfThis); } - ConcreteTypesEnvironment next() { - if (!hasNext) throw new StateError("No more elements"); + bool moveNext() { + if (counter >= size) { + _current = null; + return false; + } Element keyToIncrement = null; for (final key in concreteTypes.keys) { final iterator = state[key]; - if (iterator != null && iterator.hasNext) { - nextValues[key] = state[key].next(); + if (iterator != null && iterator.moveNext()) { + nextValues[key] = state[key].current; break; } - Iterator newIterator = concreteTypes[key].baseTypes.iterator(); + Iterator newIterator = concreteTypes[key].baseTypes.iterator; state[key] = newIterator; - nextValues[key] = newIterator.next(); + newIterator.moveNext(); + nextValues[key] = newIterator.current; } counter++; - return takeSnapshot(); + _current = takeSnapshot(); + return true; } } @@ -676,8 +683,8 @@ class ConcreteTypesInferrer { if (argumentsTypes.positional.length < signature.requiredParameterCount) { return null; } - final Iterator remainingPositionalArguments = - argumentsTypes.positional.iterator(); + final HasNextIterator remainingPositionalArguments = + new HasNextIterator(argumentsTypes.positional.iterator); // we attach each positional parameter to its corresponding positional // argument for (Link requiredParameters = signature.requiredParameters; diff --git a/sdk/lib/_internal/compiler/implementation/util/link.dart b/sdk/lib/_internal/compiler/implementation/util/link.dart index 07681c41ead..c50a3c671cc 100644 --- a/sdk/lib/_internal/compiler/implementation/util/link.dart +++ b/sdk/lib/_internal/compiler/implementation/util/link.dart @@ -4,7 +4,7 @@ part of org_dartlang_compiler_util; -class Link implements Iterable { +class Link extends Iterable { T get head => null; Link get tail => null; @@ -33,12 +33,12 @@ class Link implements Iterable { return new LinkEntry(element, this); } - Iterator iterator() => new LinkIterator(this); + Iterator get iterator => new LinkIterator(this); void printOn(StringBuffer buffer, [separatedBy]) { } - List toList() => new List(0); + List toList() => new List.fixedLength(0); bool get isEmpty => true; diff --git a/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart b/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart index 1a066b0b3c4..491bd4438b8 100644 --- a/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart +++ b/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart @@ -5,13 +5,21 @@ part of util_implementation; class LinkIterator implements Iterator { - Link current; - LinkIterator(Link this.current); - bool get hasNext => !current.isEmpty; - T next() { - T result = current.head; - current = current.tail; - return result; + T _current; + Link _link; + + LinkIterator(Link this._link); + + T get current => _current; + + bool moveNext() { + if (_link.isEmpty) { + _current = null; + return false; + } + _current = _link.head; + _link = _link.tail; + return true; } } diff --git a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart b/sdk/lib/_internal/dartdoc/bin/dartdoc.dart index 6373784b0bc..606ffb00e63 100755 --- a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart +++ b/sdk/lib/_internal/dartdoc/bin/dartdoc.dart @@ -17,6 +17,7 @@ library dartdoc; import 'dart:io'; +import 'dart:async'; // TODO(rnystrom): Use "package:" URL (#4968). import '../lib/dartdoc.dart'; diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart index 44c7d693460..784334d0f55 100644 --- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart +++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart @@ -16,10 +16,11 @@ */ library dartdoc; +import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'dart:uri'; -import 'dart:json'; +import 'dart:json' as json; import '../../compiler/implementation/mirrors/mirrors.dart'; import '../../compiler/implementation/mirrors/mirrors_util.dart'; @@ -140,7 +141,7 @@ Future compileScript(int mode, Path outputDir, Path libPath) { writeString(new File.fromPath(jsPath), jsCode); completer.complete(true); }); - result.handleException((e) => completer.completeException(e)); + result.catchError((e) => completer.completeError(e.error, e.stackTrace)); return completer.future; } @@ -336,8 +337,7 @@ class Dartdoc { void _document(Compilation compilation) { // Sort the libraries by name (not key). _sortedLibraries = new List.from( - compilation.mirrors.libraries.values.filter( - shouldIncludeLibrary)); + compilation.mirrors.libraries.values.where(shouldIncludeLibrary)); _sortedLibraries.sort((x, y) { return displayName(x).toUpperCase().compareTo( displayName(y).toUpperCase()); @@ -360,8 +360,9 @@ class Dartdoc { } startFile("apidoc.json"); - var libraries = _sortedLibraries.map( - (lib) => new LibraryElement(lib.qualifiedName, lib, _comments)); + var libraries = _sortedLibraries.mappedBy( + (lib) => new LibraryElement(lib.qualifiedName, lib, _comments)) + .toList(); write(json_serializer.serialize(libraries)); endFile(); } @@ -544,7 +545,7 @@ class Dartdoc { */ void docNavigationJson() { startFile('nav.json'); - writeln(JSON.stringify(createNavigationInfo())); + writeln(json.stringify(createNavigationInfo())); endFile(); } @@ -560,7 +561,7 @@ class Dartdoc { // Ignore. } } - String jsonString = JSON.stringify(createNavigationInfo()); + String jsonString = json.stringify(createNavigationInfo()); String dartString = jsonString.replaceAll(r"$", r"\$"); final filePath = tmpPath.append('nav.dart'); writeString(new File.fromPath(filePath), @@ -904,14 +905,14 @@ class Dartdoc { if (types == null) return; // Filter out injected types. (JavaScriptIndexingBehavior) - types = new List.from(types.filter((t) => t.library != null)); + types = new List.from(types.where((t) => t.library != null)); var publicTypes; if (showPrivate) { publicTypes = types; } else { // Skip private types. - publicTypes = new List.from(types.filter((t) => !t.isPrivate)); + publicTypes = new List.from(types.where((t) => !t.isPrivate)); } if (publicTypes.length == 0) return; @@ -1210,12 +1211,12 @@ class Dartdoc { writeln(''); } - void docMethods(ContainerMirror host, String title, List methods, + void docMethods(ContainerMirror host, String title, List methods, {bool allInherited}) { if (methods.length > 0) { writeln(''); writeln('

$title

'); - for (final method in methods) { + for (MethodMirror method in methods) { docMethod(host, method); } writeln(''); @@ -1671,6 +1672,9 @@ class Dartdoc { if (type.isVoid) { return 'void'; } + if (type.isDynamic) { + return 'dynamic'; + } if (type is TypeVariableMirror) { return type.simpleName; } @@ -1699,7 +1703,8 @@ class Dartdoc { // See if it's an instantiation of a generic type. final typeArgs = type.typeArguments; if (typeArgs.length > 0) { - final args = Strings.join(typeArgs.map((arg) => typeName(arg)), ', '); + final args = + Strings.join(typeArgs.mappedBy((arg) => typeName(arg)), ', '); return '${type.originalDeclaration.simpleName}<$args>'; } diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart index 9be17a3236b..4f27fc3e216 100644 --- a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart +++ b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart @@ -6,7 +6,7 @@ library client_live_nav; import 'dart:html'; -import 'dart:json'; +import 'dart:json' as jsonlib; import '../../../../compiler/implementation/source_file.dart'; // TODO(rnystrom): Use "package:" URL (#4968). import '../../classify.dart'; @@ -23,7 +23,7 @@ main() { // Request the navigation data so we can build the HTML for it. new HttpRequest.get('${prefix}nav.json', (request) { - var json = JSON.parse(request.responseText); + var json = jsonlib.parse(request.responseText); buildNavigation(json); setupSearch(json); }); diff --git a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart index cb52f96d6c5..79a9aa64dfc 100644 --- a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart +++ b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart @@ -49,7 +49,7 @@ String unindent(String text, int indentation) { } /** Sorts the map by the key, doing a case-insensitive comparison. */ -List orderByName(Collection list) { +List orderByName(Iterable list) { final elements = new List.from(list); elements.sort((a,b) { String aName = a.simpleName.toLowerCase(); diff --git a/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart b/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart index d67cd72e2bc..8039d0c9c45 100755 --- a/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart +++ b/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart @@ -9,8 +9,9 @@ */ library json_serializer; +import 'dart:async'; import 'dart:mirrors'; -import 'dart:json'; +import 'dart:json' as json; String serialize(Object o) { var printer = new JsonPrinter(); @@ -45,9 +46,8 @@ void _serializeObject(String name, Object o, JsonPrinter printer) { // TODO(jacobr): this code works only because futures for mirrors return // immediately. for(String memberName in members) { - mirror.getField(memberName).then((result) { - _serialize(memberName, result.reflectee, printer); - }); + var result = deprecatedFutureValue(mirror.getField(memberName)); + _serialize(memberName, result.reflectee, printer); } printer.endObject(); } @@ -185,7 +185,7 @@ class JsonPrinter { } else { // Convenient hack to remove the pretty printing this serializer adds by // default. - return JSON.stringify(JSON.parse(_sb.toString())); + return json.stringify(json.parse(_sb.toString())); } } diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart index afda7ad1c73..67109a45fee 100644 --- a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart +++ b/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart @@ -135,7 +135,7 @@ abstract class BlockSyntax { /// Gets whether or not [parser]'s current line should end the previous block. static bool isAtBlockEnd(BlockParser parser) { if (parser.isDone) return true; - return syntaxes.some((s) => s.canParse(parser) && s.canEndBlock); + return syntaxes.any((s) => s.canParse(parser) && s.canEndBlock); } } diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart index d44c5f51e47..1695e96b7d3 100644 --- a/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart +++ b/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart @@ -39,7 +39,7 @@ class HtmlRenderer implements NodeVisitor { // Sort the keys so that we generate stable output. // TODO(rnystrom): This assumes keys returns a fresh mutable // collection. - final attributeNames = element.attributes.keys; + final attributeNames = element.attributes.keys.toList(); attributeNames.sort((a, b) => a.compareTo(b)); for (final name in attributeNames) { buffer.add(' $name="${element.attributes[name]}"'); diff --git a/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart b/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart index 3b9b534ebd3..f93c6fc35c4 100644 --- a/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart +++ b/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart @@ -146,7 +146,7 @@ Future _runDartdoc(List arguments, {int exitCode: 0}) { var dartdoc = 'bin/dartdoc.dart'; arguments.insertRange(0, 1, dartdoc); return Process.run(dartBin, arguments) - .transform((result) { + .then((result) { expect(result.exitCode, exitCode); }); } diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart index 29961b060bd..709bf8a3acb 100644 --- a/sdk/lib/_internal/libraries.dart +++ b/sdk/lib/_internal/libraries.dart @@ -22,9 +22,11 @@ const int VM_PLATFORM = 2; */ const Map LIBRARIES = const { - "collection": const LibraryInfo( - "collection/collection.dart", - implementation: true), + "async": const LibraryInfo( + "async/async.dart", + dart2jsPatchPath: "_internal/compiler/implementation/lib/async_patch.dart"), + + "collection": const LibraryInfo("collection/collection.dart"), "core": const LibraryInfo( "core/core.dart", diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart new file mode 100644 index 00000000000..220761cfe26 --- /dev/null +++ b/sdk/lib/async/async.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2012, 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. + +library dart.async; + +part 'async_error.dart'; +part 'future.dart'; +part 'future_impl.dart'; +part 'merge_stream.dart'; +part 'signal.dart'; +part 'stream.dart'; +part 'stream_controller.dart'; +part 'stream_impl.dart'; +part 'stream_pipe.dart'; +part 'string_transform.dart'; +part 'timer.dart'; diff --git a/sdk/lib/async/async_error.dart b/sdk/lib/async/async_error.dart new file mode 100644 index 00000000000..aad80b7f8b5 --- /dev/null +++ b/sdk/lib/async/async_error.dart @@ -0,0 +1,74 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +/** + * Error result of an asynchronous computation. + */ +class AsyncError { + /** The actual error thrown by the computation. */ + final Object error; + /** Stack trace corresponding to the error, if available. */ + final Object stackTrace; + /** Asynchronous error leading to this error, if error handling fails. */ + final AsyncError cause; + + // TODO(lrn): When possible, combine into one constructor with both optional + // positional and named arguments. + AsyncError(Object this.error, [Object this.stackTrace]): cause = null; + AsyncError.withCause(Object this.error, Object this.stackTrace, this.cause); + + void _writeOn(StringBuffer buffer) { + buffer.add("'"); + String message; + try { + message = error.toString(); + } catch (e) { + message = Error.safeToString(error); + } + buffer.add(message); + buffer.add("'\n"); + if (stackTrace != null) { + buffer.add("Stack trace:\n"); + buffer.add(stackTrace.toString()); + buffer.add("\n"); + } + } + + String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.add("AsyncError: "); + _writeOn(buffer); + AsyncError cause = this.cause; + while (cause != null) { + buffer.add("Caused by: "); + cause._writeOn(buffer); + cause = cause.cause; + } + return buffer.toString(); + } + + throwDelayed() { + reportError() { + print("Uncaught Error: $error"); + if (stackTrace != null) { + print("Stack Trace:\n$stackTrace\n"); + } + } + + try { + new Timer(0, (_) { + reportError(); + // TODO(floitsch): we potentially want to call the global error handler + // directly so that we can pass the stack trace. + throw error; + }); + } catch (e) { + // Unfortunately there is not much more we can do... + reportError(); + } + } +} + diff --git a/sdk/lib/async/async_sources.gypi b/sdk/lib/async/async_sources.gypi new file mode 100644 index 00000000000..b0f4fe8e7ae --- /dev/null +++ b/sdk/lib/async/async_sources.gypi @@ -0,0 +1,21 @@ +# Copyright (c) 2012, 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. + +# This file contains all sources for the dart:collection library. +{ + 'sources': [ + 'async_error.dart', + 'future.dart', + 'future_impl.dart', + 'merge_stream.dart', + 'signal.dart', + 'stream.dart', + 'stream_controller.dart', + 'stream_impl.dart', + 'stream_pipe.dart', + 'string_transform.dart', + 'timer.dart', + ], +} + diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart new file mode 100644 index 00000000000..c787f79c1ea --- /dev/null +++ b/sdk/lib/async/future.dart @@ -0,0 +1,186 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +/** + * A [Future] is used to obtain a value sometime in the future. Receivers of a + * [Future] can obtain the value by passing a callback to [then]. For example: + * + * Future future = getFutureFromSomewhere(); + * future.then((value) { + * print("I received the number $value"); + * }); + * + * A future may complete by *succeeding* (producing a value) or *failing* + * (producing an error, which may be handled with [catchError]). + * + * When a future completes, the following actions happen in order: + * + * 1. if the future suceeded, handlers registered with [then] are called. + * 2. if the future failed, handlers registered with [catchError] are + * tested in sequence. Each test returning true is, have its handler + * called. + * 4. if the future failed, and no handler registered with [catchError] it + * is accepting the error, an error is sent to the global error handler. + * + * [Future]s are usually not created directly, but with [Completer]s. + */ +abstract class Future { + /** A future whose value is immediately available. */ + factory Future.immediate(T value) => new _FutureImpl.immediate(value); + + /** A future that completes with an error. */ + factory Future.immediateError(var error, [Object stackTrace]) { + return new _FutureImpl.immediateError(error, stackTrace); + } + + // TODO(floitsch): I don't think the typing is right here. + // Otherwise new Future.wait(...) would be a Future>. Sounds + // wrong. + factory Future.wait(List futures) + => new _FutureImpl>.wait(futures); + + factory Future.delayed(int milliseconds, dynamic value()) { + var completer = new Completer(); + new Timer(milliseconds, (_) => completer.complete(null)); + return completer.future.then((_) => value()); + } + + /** + * When this future completes with a value, then [onValue] is called with this + * value. If [this] future is already completed then the invocation of + * [onValue] is delayed until the next event-loop iteration. + * + * Returns a new [Future] [:f:]. + * + * If [this] is completed with an error then [:f:] is completed with the same + * error. If [this] is completed with a value, then [:f:]'s completion value + * depends on the result of invoking [onValue] with [this]' completion value. + * + * If [onValue] returns a [Future] [:f2:] then [:f:] and [:f2:] are chained. + * That is, [:f:] is completed with the completion value of [:f2:]. + * + * Otherwise [:f:] is completed with the return value of [onValue]. + * + * If [onValue] throws an exception, the returned future will receive the + * exception. + * + * If [onError] is provided, it is called if this future completes with an + * error, and its return value/throw behavior is handled the same way as + * for [onValue]. + * + * In most cases, it is more readable to use [catchError] separately, possibly + * with a [:test:] parameter, instead of handling both value and error in a + * single [then] call. + */ + Future then(onValue(T value), { onError(AsyncError asyncError) }); + + /** + * If this future is complete with an error, [test] is called with the error. + * If [test] returns [true], [onError] is called with the error + * wrapped in an [AsyncError]. The result of [onError] is handled exactly as + * [then]'s [onValue]. If [test] returns false, the exception is not handled + * by [onError]. If [test] is omitted, it defaults to a function that always + * returns true. + * + * Example: + * foo + * .catchError(..., test: (e) => e is ArgumentError) + * .catchError(..., test: (e) => e is NoSuchMethodError) + * .then((v) { ... }); + */ + Future catchError(onError(AsyncError asyncError), + {bool test(Object error)}); + + /** + * Register a function to be called when this future completes. + * + * The [action] function is called when this future completes, whether it + * does so with a value or with an error. + * + * This is the asynchronous equivalent of a "finally" block. + * + * If the call to [action] does not throw, the returned future is completed + * with the same result as this future. + * + * If the call to [action] throws, the returned future is completed with the + * thrown error. + */ + Future whenComplete(void action()); + + /** + * Creates a [Stream] that sends [this]' completion value, data or error, to + * its subscribers. The stream closes after the completion value. + */ + Stream asStream(); +} + +/** + * A [Completer] is used to produce [Future]s and supply their value when it + * becomes available. + * + * A service that provides values to callers, and wants to return [Future]s can + * use a [Completer] as follows: + * + * Completer completer = new Completer(); + * // send future object back to client... + * return completer.future; + * ... + * + * // later when value is available, call: + * completer.complete(value); + * + * // alternatively, if the service cannot produce the value, it + * // can provide an exception: + * completer.completeException(exception); + * + */ +abstract class Completer { + + factory Completer() => new _CompleterImpl(); + + /** The future that will contain the value produced by this completer. */ + Future get future; + + /** Supply a value for [future]. */ + void complete(T value); + + /** + * Indicate in [future] that an exception occured while trying to produce its + * value. The argument [exception] should not be [:null:]. A [stackTrace] + * object can be provided as well to give the user information about where + * the error occurred. If omitted, it will be [:null:]. + */ + void completeError(Object exception, [Object stackTrace]); +} + +class Futures { + /** + * Returns a future which will complete once all the futures in a list are + * complete. If any of the futures in the list completes with an exception, + * the resulting future also completes with an exception. (The value of the + * returned future will be a list of all the values that were produced.) + */ + static Future wait(Iterable futures) { + return new _FutureImpl.wait(futures); + } + + /** + * Runs [f] for each element in [input] in order, moving to the next element + * only when the [Future] returned by [f] completes. Returns a [Future] that + * completes when all elements have been processed. + * + * The return values of all [Future]s are discarded. Any errors will cause the + * iteration to stop and will be piped through the returned [Future]. + */ + static Future forEach(Iterable input, Future f(element)) { + var iterator = input.iterator; + Future nextElement(_) { + if (!iterator.moveNext()) return new Future.immediate(null); + return f(iterator.current).then(nextElement); + } + return nextElement(null); + } +} diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart new file mode 100644 index 00000000000..bf071e0e7bc --- /dev/null +++ b/sdk/lib/async/future_impl.dart @@ -0,0 +1,460 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +deprecatedFutureValue(_FutureImpl future) => + future._isComplete ? future._resultOrListeners : null; + + +class _CompleterImpl implements Completer { + final Future future; + bool _isComplete = false; + + _CompleterImpl() : future = new _FutureImpl(); + + void complete(T value) { + if (_isComplete) throw new StateError("Future already completed"); + _isComplete = true; + _FutureImpl future = this.future; + future._setValue(value); + } + + void completeError(Object error, [Object stackTrace = null]) { + if (_isComplete) throw new StateError("Future already completed"); + _isComplete = true; + new Timer(0, (_) { + // Never complete an error in the same cycle. Otherwise users might + // not have a chance to register their error-handlers. + _FutureImpl future = this.future; + future._setError(new AsyncError(error, stackTrace)); + }); + } +} + +/** + * A listener on a future. + * + * When the future completes, the [_sendValue] or [_sendError] method + * is invoked with the result. + * + * Listeners are kept in a linked list. + */ +abstract class _FutureListener { + _FutureListener _nextListener; + factory _FutureListener.wrap(_FutureImpl future) { + return new _FutureListenerWrapper(future); + } + void _sendValue(T value); + void _sendError(AsyncError error); +} + +/** Adapter for a [_FutureImpl] to be a future result listener. */ +class _FutureListenerWrapper implements _FutureListener { + _FutureImpl future; + _FutureListener _nextListener; + _FutureListenerWrapper(this.future); + _sendValue(T value) { future._setValue(value); } + _sendError(AsyncError error) { future._setError(error); } +} + +class _FutureImpl implements Future { + static const int _INCOMPLETE = 0; + static const int _VALUE = 1; + static const int _ERROR = 2; + + /** Whether the future is complete, and as what. */ + int _state = _INCOMPLETE; + + bool get _isComplete => _state != _INCOMPLETE; + bool get _hasValue => _state == _VALUE; + bool get _hasError => _state == _ERROR; + + /** + * Either the result, or a list of listeners until the future completes. + * + * The result of the future is either a value or an [AsyncError]. + * A result is only stored when the future has completed. + * + * The listeners is an internally linked list of [_FutureListener]s. + * Listeners are only remembered while the future is not yet complete. + * + * Since the result and the listeners cannot occur at the same time, + * we can use the same field for both. + */ + var _resultOrListeners; + + _FutureImpl(); + + _FutureImpl.immediate(T value) { + _state = _VALUE; + _resultOrListeners = value; + } + + _FutureImpl.immediateError(var error, [Object stackTrace]) { + new Timer(0, (_) { _setError(new AsyncError(error, stackTrace)); }); + } + + factory _FutureImpl.wait(Iterable futures) { + // TODO(ajohnsen): can we do better wrt the generic type T? + if (futures.isEmpty) { + return new Future.immediate(const []); + } + + Completer completer = new Completer(); + int remaining = futures.length; + List values = new List.fixedLength(futures.length); + + // As each future completes, put its value into the corresponding + // position in the list of values. + int i = 0; + for (Future future in futures) { + int pos = i++; + future.then((Object value) { + values[pos] = value; + if (--remaining == 0) { + completer.complete(values); + } + }); + future.catchError((error) { + completer.completeError(error.error, error.stackTrace); + }); + } + + return completer.future; + } + + Future then(f(T value), { onError(AsyncError error) }) { + if (!_isComplete) { + if (onError == null) { + return new _ThenFuture(f).._subscribeTo(this); + } + return new _SubscribeFuture(f, onError).._subscribeTo(this); + } + if (_hasError) { + if (onError != null) { + return _handleError(onError, null); + } + // The "f" funtion will never be called, so just return + // a future that delegates to this. We don't want to return + // this itself to give a signal that the future is complete. + return new _FutureWrapper(this); + } else { + assert(_hasValue); + return _handleValue(f); + } + } + + Future catchError(f(AsyncError asyncError), { bool test(error) }) { + if (_hasValue) { + return new _FutureWrapper(this); + } + if (!_isComplete) { + return new _CatchErrorFuture(f, test).._subscribeTo(this); + } else { + return _handleError(f, test); + } + } + + Future whenComplete(void action()) { + _WhenFuture whenFuture = new _WhenFuture(action); + if (!_isComplete) { + _addListener(whenFuture); + } else if (_hasValue) { + new Timer(0, (_) { + T value = _resultOrListeners; + whenFuture._sendValue(value); + }); + } else { + assert(_hasError); + new Timer(0, (_) { + AsyncError error = _resultOrListeners; + whenFuture._sendError(error); + }); + } + return whenFuture; + } + + Future _handleValue(onValue(var value)) { + assert(_hasValue); + _ThenFuture thenFuture = new _ThenFuture(onValue); + T value = _resultOrListeners; + new Timer(0, (_) { thenFuture._sendValue(value); }); + return thenFuture; + } + + Future _handleError(onError(AsyncError error), bool test(error)) { + assert(_hasError); + AsyncError error = _resultOrListeners; + _CatchErrorFuture errorFuture = new _CatchErrorFuture(onError, test); + new Timer(0, (_) { errorFuture._sendError(error); }); + return errorFuture; + } + + Stream asStream() => new Stream.fromFuture(this); + + void _setValue(T value) { + if (_state != _INCOMPLETE) throw new StateError("Future already completed"); + _FutureListener listeners = _removeListeners(); + _state = _VALUE; + _resultOrListeners = value; + while (listeners != null) { + _FutureListener listener = listeners; + listeners = listener._nextListener; + listener._nextListener = null; + listener._sendValue(value); + } + } + + void _setError(AsyncError error) { + if (_isComplete) throw new StateError("Future already completed"); + _FutureListener listeners = _removeListeners(); + _state = _ERROR; + _resultOrListeners = error; + if (listeners == null) { + error.throwDelayed(); + return; + } + while (listeners != null) { + _FutureListener listener = listeners; + listeners = listener._nextListener; + listener._nextListener = null; + listener._sendError(error); + } + } + + void _addListener(_FutureListener listener) { + assert(!_isComplete); + assert(listener._nextListener == null); + listener._nextListener = _resultOrListeners; + _resultOrListeners = listener; + } + + _FutureListener _removeListeners() { + // Reverse listeners before returning them, so the resulting list is in + // subscription order. + assert(!_isComplete); + _FutureListener current = _resultOrListeners; + _resultOrListeners = null; + _FutureListener prev = null; + while (current != null) { + _FutureListener next = current._nextListener; + current._nextListener = prev; + prev = current; + current = next; + } + return prev; + } + + /** + * Make another [_FutureImpl] receive the result of this one. + * + * If this future is already complete, the [future] is notified + * immediately. This function is only called during event resolution + * where it's acceptable to send an event. + */ + void _chain(_FutureImpl future) { + if (!_isComplete) { + _addListener(future._asListener()); + } else if (_hasValue) { + future._setValue(_resultOrListeners); + } else { + assert(_hasError); + future._setError(_resultOrListeners); + } + } + + _FutureListener _asListener() => new _FutureListener.wrap(this); +} + +/** + * Transforming future base class. + * + * A transforming future is itself a future and a future listener. + * Subclasses override [_sendValue]/[_sendError] to intercept + * the results of a previous future. + */ +abstract class _TransformFuture extends _FutureImpl + implements _FutureListener { + // _FutureListener implementation. + _FutureListener _nextListener; + + void _sendValue(S value); + + void _sendError(AsyncError error); + + void _subscribeTo(_FutureImpl future) { + future._addListener(this); + } + + /** + * Helper function to hand the result of transforming an incoming event. + * + * If the result is itself a [Future], this future is linked to that + * future's output. If not, this future is completed with the result. + */ + void _setOrChainValue(var result) { + if (result is Future) { + // Result should be a Future. + if (result is _FutureImpl) { + _FutureImpl chainFuture = result; + chainFuture._chain(this); + return; + } else { + Future future = result; + future.then(_setValue, + onError: _setError); + return; + } + } else { + // Result must be of type T. + _setValue(result); + } + } +} + +/** The onValue and onError handlers return either a value or a future */ +typedef dynamic _FutureOnValue(T value); +typedef dynamic _FutureOnError(AsyncError error); +/** Test used by [Future.catchError] to handle skip some errors. */ +typedef bool _FutureErrorTest(var error); +/** Used by [WhenFuture]. */ +typedef void _FutureAction(); + +/** Future returned by [Future.then] with no [:onError:] parameter. */ +class _ThenFuture extends _TransformFuture { + final _FutureOnValue _onValue; + + _ThenFuture(this._onValue); + + _sendValue(S value) { + assert(_onValue != null); + var result; + try { + result = _onValue(value); + } catch (e, s) { + _setError(new AsyncError(e, s)); + return; + } + _setOrChainValue(result); + } + + void _sendError(AsyncError error) { + _setError(error); + } +} + +/** Future returned by [Future.catchError]. */ +class _CatchErrorFuture extends _TransformFuture { + final _FutureErrorTest _test; + final _FutureOnError _onError; + + _CatchErrorFuture(this._onError, this._test); + + _sendValue(T value) { + _setValue(value); + } + + _sendError(AsyncError error) { + assert(_onError != null); + // if _test is supplied, check if it returns true, otherwise just + // forward the error unmodified. + if (_test != null) { + bool matchesTest; + try { + matchesTest = _test(error.error); + } catch (e, s) { + _setError(new AsyncError.withCause(e, s, error)); + return; + } + if (!matchesTest) { + _setError(error); + return; + } + } + // Act on the error, and use the result as this future's result. + var result; + try { + result = _onError(error); + } catch (e, s) { + _setError(new AsyncError.withCause(e, s, error)); + return; + } + _setOrChainValue(result); + } +} + +/** Future returned by [Future.then] with an [:onError:] parameter. */ +class _SubscribeFuture extends _ThenFuture { + final _FutureOnError _onError; + + _SubscribeFuture(onValue(S value), this._onError) : super(onValue); + + // The _sendValue method is inherited from ThenFuture. + + void _sendError(AsyncError error) { + assert(_onError != null); + var result; + try { + result = _onError(error); + } catch (e, s) { + _setError(new AsyncError.withCause(e, s, error)); + return; + } + _setOrChainValue(result); + } +} + +/** Future returned by [Future.whenComplete]. */ +class _WhenFuture extends _TransformFuture { + final _FutureAction _action; + + _WhenFuture(this._action); + + void _sendValue(T value) { + try { + _action(); + } catch (e, s) { + _setError(new AsyncError(e, s)); + return; + } + _setValue(value); + } + + void _sendError(AsyncError error) { + try { + _action(); + } catch (e, s) { + error = new AsyncError.withCause(e, s, error); + } + _setError(error); + } +} + +/** + * Thin wrapper around a [Future]. + * + * This is used to return a "new" [Future] that effectively work just + * as an existing [Future], without making this discoverable by comparing + * identities. + */ +class _FutureWrapper implements Future { + final Future _future; + + _FutureWrapper(this._future); + + Future then(function(T value), { onError(AsyncError error) }) { + return _future.then(function, onError: onError); + } + + Future catchError(function(AsyncError error), {bool test(var error)}) { + return _future.catchError(function, test: test); + } + + Future whenComplete(void action()) { + return _future.whenComplete(action); + } + + Stream asStream() => new Stream.fromFuture(this); +} diff --git a/sdk/lib/async/merge_stream.dart b/sdk/lib/async/merge_stream.dart new file mode 100644 index 00000000000..2a9d273e2cd --- /dev/null +++ b/sdk/lib/async/merge_stream.dart @@ -0,0 +1,282 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +class _SupercedeEntry { + final SupercedeStream stream; + Stream source; + StreamSubscription subscription = null; + _SupercedeEntry next; + + _SupercedeEntry(this.stream, this.source, this.next); + + // Whether the source stream is complete. + bool get isDone => source == null; + + void onData(T data) { + // Stop all lower-priority sources. + stream._setData(this, data); + } + + void onError(AsyncError error) { + stream._signalError(error); + } + + void onDone() { + subscription = null; + source = null; + stream._setDone(this); + } + + void start() { + assert(subscription == null); + if (!isDone) { + subscription = + source.listen(onData, onError: onError, onDone: onDone); + } + } + + void stop() { + if (!isDone) { + subscription.cancel(); + subscription = null; + } + } + + void pause() { + if (!isDone) subscription.pause(); + } + + void resume() { + if (!isDone) subscription.resume(); + } +} + +/** + * [Stream] that forwards data from its active source with greatest priority. + * + * The [SupercedeStream] gets data from some source [Stream]s which + * are ordered in order of increasing priority. + * When a higher priority stream provides data, all lower priority streams + * are dropped. + * + * Errors from all (undropped) streams are forwarded. + */ +class SupercedeStream extends _MultiStreamImpl { + _SupercedeEntry _entries = null; + + /** + * Create [SupercedeStream] from the given [sources]. + * + * The [sources] are iterated in order of increasing priority. + */ + SupercedeStream(Iterable> sources) { + // Set up linked list of sources in decreasing priority order. + // The order allows us to drop all lower priority streams when a higher + // priority stream provides a value. + for (Stream stream in sources) { + _entries = new _SupercedeEntry(this, stream, _entries); + } + } + + void _onSubscriptionStateChange() { + if (_hasSubscribers) { + for (_SupercedeEntry entry = _entries; + entry != null; + entry = entry.next) { + entry.start(); + } + } else { + for (_SupercedeEntry entry = _entries; + entry != null; + entry = entry.next) { + entry.stop(); + } + } + } + + void _onPauseStateChange() { + if (_isPaused) { + for (_SupercedeEntry entry = _entries; + entry != null; + entry = entry.next) { + entry.pause(); + } + } else { + for (_SupercedeEntry entry = _entries; + entry != null; + entry = entry.next) { + entry.resume(); + } + } + } + + void _setData(_SupercedeEntry entry, T data) { + while (entry.next != null) { + _SupercedeEntry nextEntry = entry.next; + entry.next = null; + nextEntry.stop(); + entry = nextEntry; + } + _add(data); + } + + void _setDone(_SupercedeEntry entry) { + if (identical(_entries, entry)) { + // Remove the leading completed streams. These are streams + // the completed without ever providing data. + while (_entries.isDone) { + _entries = _entries.next; + if (_entries == null) { + _close(); + return; + } + } + } + // Otherwise we leave the completed entry in the list and + // remove it when a higher priority stream provides data or + // all higher priority streams have completed. + } +} + +/** + * Helper class for [CyclicScheduleStream]. + * + * Used to maintain a list of source streams which are activated in cyclic + * order. + * + * The stream is either unsubscribed, paused or active. Only one stream + * will be active at a time. A source is not subscribed until it's first + * activated. + * + * If the source completes, the entry is removed from [stream]. + */ +class _CycleEntry { + final CyclicScheduleStream stream; + /** A single source stream for the [CyclicScheduleStream]. */ + Stream source; + /** The active subscription, if any. */ + StreamSubscription subscription = null; + /** Next entry in a linked list of entries. */ + _CycleEntry next; + + _CycleEntry(this.stream, this.source); + + void cancel() { + // This method may be called event if this entry has never been activated. + if (subscription != null) { + subscription.cancel(); + subscription = null; + } + } + + void pause() { + ensureSubscribed(); + if (!subscription.isPaused) { + subscription.pause(); + } + } + + void activate() { + ensureSubscribed(); + if (subscription.isPaused) { + subscription.resume(); + } + } + + void ensureSubscribed() { + if (subscription == null) { + subscription = + source.listen(stream._onData, + onError: stream._signalError, + onDone: stream._onDone); + } + } +} + +/** + * [Stream] that schedules events from multiple sources in cyclic order. + * + * The source streams are activated and paused so that only one data event + * is generated at a time, and those data events are output on this stream. + * + * Error events from the currently active stream are forwarded without + * changing the schedule. When a source stream ends, it is removed from + * the schedule. + */ +class CyclicScheduleStream extends _MultiStreamImpl { + _CycleEntry _currentEntry = null; + _CycleEntry _lastEntry = null; + + /** + * Create a [Stream] that provides data from [sources] one event at a time. + * + * The data are provided as one event from each stream in the order they are + * given by the [Iterable], and then cycling as long as there are data. + */ + CyclicScheduleStream(Iterable> sources) { + _CycleEntry entry = null; + for (Stream source in sources) { + _CycleEntry newEntry = new _CycleEntry(this, source); + if (_lastEntry == null) { + _currentEntry = _lastEntry = newEntry; + } else { + _lastEntry = _lastEntry.next = newEntry; + } + } + if (_currentEntry == null) { + _close(); + } + } + + void _onSubscriptionStateChange() { + if (_hasSubscribers) { + _currentEntry.activate(); + for (_CycleEntry entry = _currentEntry.next; + entry != null; + entry = entry.next) { + entry.pause(); + } + return; + } + for (_CycleEntry entry = _currentEntry; entry != null; entry = entry.next) { + entry.cancel(); + } + } + + void _onPauseStateChange() { + if (_isPaused) { + _currentEntry.pause(); + } else { + _currentEntry.activate(); + } + } + + void _onData(T data) { + if (_currentEntry.next != null) { + _currentEntry.pause(); + _add(data); + // Move the current entry to the end of the list. + _lastEntry = _lastEntry.next = _currentEntry; + _currentEntry = _currentEntry.next; + _lastEntry.next = null; + _currentEntry.activate(); + } else { + // No pausing with only one entry left. + _add(data); + } + } + + void _onDone() { + if (_currentEntry.next == null) { + _close(); + _currentEntry = _lastEntry = null; + } else { + // Remove the current entry from the list now that it's complete. + _currentEntry = _currentEntry.next; + _currentEntry.activate(); + } + } +} diff --git a/sdk/lib/async/signal.dart b/sdk/lib/async/signal.dart new file mode 100644 index 00000000000..723de385d69 --- /dev/null +++ b/sdk/lib/async/signal.dart @@ -0,0 +1,90 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +/** + * A basic asynchronous notification. + */ +abstract class Signal { + factory Signal.delayed(int milliseconds) { + var completer = new SignalCompleter(); + new Timer(milliseconds, (_) => completer.complete()); + return completer.signal; + } + /** + * The [onComplete] handler is called when the signal completes. + * + * If the signal is already complete, the [onComplete] handler is called + * as soon as possible, but no sooner than the next time an event is fired. + */ + void then(void onComplete()); +} + +typedef _SignalCompleteHandler(); + +/** + * Simple [Signal] controller that creates a [Signal] and allows completing it. + */ +class SignalCompleter { + final Signal signal; + SignalCompleter() : signal = new _SignalImpl(); + void complete() { + _SignalImpl mySignal = signal; + mySignal._complete(); + } +} + +/** + * Simple Signal implementation receiving its completion from a + * [SignalCompleter]. + */ +class _SignalImpl implements Signal { + /** Single-linked list of "done" event handlers to notify. */ + _SignalListener _listeners = null; + + /** Whether the signal is already completed. */ + bool _isComplete = false; + + void then(void onComplete()) { + _listeners = new _SignalListener(_listeners, onComplete); + if (_isComplete) { + // Schedule the done events as soon as the event queue is ready. + new Timer(0, (Timer timer) { _sendDone(); }); + } + } + + /** + * Complete the signal. + * + * This immediately notifies all listeners on the signal. + */ + void _complete() { + assert(!_isComplete); // Only complete once. + _isComplete = true; + _sendDone(); + } + + /** + * Notify all listeners. + */ + void _sendDone() { + while (_listeners != null) { + _DoneHandler onDone = _listeners.listener; + _listeners = _listeners.next; + try { + onDone(); + } catch (e, s) { + new AsyncError(e, s).throwDelayed(); + } + } + } +} + +/** Single-linked list element of the listeners on a [_SignalImpl]. */ +class _SignalListener { + _SignalListener next; + _SignalCompleteHandler listener; + _SignalListener(this.next, this.listener); +} diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart new file mode 100644 index 00000000000..ffa10233ca0 --- /dev/null +++ b/sdk/lib/async/stream.dart @@ -0,0 +1,838 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +// ------------------------------------------------------------------- +// Core Stream types +// ------------------------------------------------------------------- + +abstract class Stream { + Stream(); + + factory Stream.fromFuture(Future future) { + var controller = new StreamController(); + future.then((value) { + controller.add(value); + controller.close(); + }, + onError: (error) { + controller.signalError(error); + controller.close(); + }); + return controller.stream; + } + + /** + * Stream that outputs events from the [sources] in cyclic order. + * + * The merged streams are paused and resumed in order to ensure the proper + * order of output events. + */ + factory Stream.cyclic(Iterable sources) = CyclicScheduleStream; + + /** + * Create a stream that forwards data from the highest priority active source. + * + * Sources are provided in order of increasing priority, and only data from + * the highest priority source stream that has provided data are output + * on the created stream. + * + * Errors from the most recent active stream, and any higher priority stream, + * are forwarded to the created stream. + * + * If a higher priority source stream completes without providing data, + * it will have no effect on lower priority streams. + */ + factory Stream.superceding(Iterable> sources) = SupercedeStream; + + /** + * Add a subscription to this stream. + * + * On each data event from this stream, the subscribers [onData] handler + * is called. If [onData] is null, nothing happens. + * + * On errors from this stream, the [onError] handler is given a + * [AsyncError] object describing the error. + * + * If this stream closes, the [onDone] handler is called. + * + * If [unsubscribeOnError] is true, the subscription is ended when + * the first error is reported. The default is false. + */ + StreamSubscription listen(void onData(T event), + { void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError}); + + /** + * Creates a new stream from this stream that discards some data events. + * + * The new stream sends the same error and done events as this stream, + * but it only sends the data events that satisfy the [test]. + */ + Stream where(bool test(T event)) { + return this.transform(new WhereStream(test)); + } + + /** + * Create a new stream that converts each element of this stream + * to a new value using the [convert] function. + */ + Stream mappedBy(convert(T event)) { + return this.transform(new MapStream(convert)); + } + + /** + * Create a wrapper Stream that intercepts some errors from this stream. + * + * If the handler returns null, the error is considered handled. + * Otherwise the returned [AsyncError] is passed to the subscribers + * of the stream. + */ + Stream handleError(AsyncError handle(AsyncError error)) { + return this.transform(new HandleErrorStream(handle)); + } + + /** + * Create a new stream from this stream that converts each element + * into zero or more events. + * + * Each incoming event is converted to an [Iterable] of new events, + * and each of these new events are then sent by the returned stream + * in order. + */ + Stream expand(Iterable convert(T value)) { + return this.transform(new ExpandStream(convert)); + } + + /** + * Bind this stream as the input of the provided [StreamConsumer]. + */ + Future pipe(StreamConsumer streamConsumer) { + return streamConsumer.consume(this); + } + + /** + * Chain this stream as the input of the provided [StreamTransformer]. + * + * Returns the result of [:streamTransformer.bind:] itself. + */ + Stream transform(StreamTransformer streamTransformer) { + return streamTransformer.bind(this); + } + + + /** Reduces a sequence of values by repeatedly applying [combine]. */ + Future reduce(var initialValue, combine(var previous, T element)) { + Completer completer = new Completer(); + var value = initialValue; + StreamSubscription subscription; + subscription = this.listen( + (T element) { + try { + value = combine(value, element); + } catch (e, s) { + subscription.cancel(); + completer.completeError(e, s); + } + }, + onError: (AsyncError e) { + completer.completeError(e.error, e.stackTrace); + }, + onDone: () { + completer.complete(value); + }, + unsubscribeOnError: true); + return completer.future; + } + + // Deprecated method, previously called 'pipe', retained for compatibility. + Signal pipeInto(Sink sink, + {void onError(AsyncError error), + bool unsubscribeOnError}) { + SignalCompleter completer = new SignalCompleter(); + this.listen( + sink.add, + onError: onError, + onDone: () { + sink.close(); + completer.complete(); + }, + unsubscribeOnError: unsubscribeOnError); + return completer.signal; + } + + + /** + * Check whether [match] occurs in the elements provided by this stream. + * + * Completes the [Future] when the answer is known. + * If this stream reports an error, the [Future] will report that error. + */ + Future contains(T match) { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (T element) { + if (element == match) { + subscription.cancel(); + future._setValue(true); + } + }, + onError: future._setError, + onDone: () { + future._setValue(false); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Check whether [test] accepts all elements provided by this stream. + * + * Completes the [Future] when the answer is known. + * If this stream reports an error, the [Future] will report that error. + */ + Future every(bool test(T element)) { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (T element) { + if (!test(element)) { + subscription.cancel(); + future._setValue(false); + } + }, + onError: future._setError, + onDone: () { + future._setValue(true); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Check whether [test] accepts any element provided by this stream. + * + * Completes the [Future] when the answer is known. + * If this stream reports an error, the [Future] will report that error. + */ + Future any(bool test(T element)) { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (T element) { + if (test(element)) { + subscription.cancel(); + future._setValue(true); + } + }, + onError: future._setError, + onDone: () { + future._setValue(false); + }, + unsubscribeOnError: true); + return future; + } + + + /** Counts the elements in the stream. */ + Future get length { + _FutureImpl future = new _FutureImpl(); + int count = 0; + this.listen( + (_) { count++; }, + onError: future._setError, + onDone: () { + future._setValue(count); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Finds the least element in the stream. + * + * If the stream is empty, the result is [:null:]. + * Otherwise the result is a value from the stream that is not greater + * than any other value from the stream (according to [compare], which must + * be a [Comparator]). + * + * If [compare] is omitted, it defaults to [Comparable.compare]. + */ + Future min([int compare(T a, T b)]) { + if (compare == null) compare = Comparable.compare; + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + T min = null; + subscription = this.listen( + (T value) { + min = value; + subscription.onData((T value) { + if (compare(min, value) > 0) min = value; + }); + }, + onError: future._setError, + onDone: () { + future._setValue(min); + }, + unsubscribeOnError: true + ); + return future; + } + + /** + * Finds the least element in the stream. + * + * If the stream is empty, the result is [:null:]. + * Otherwise the result is an value from the stream that is not greater + * than any other value from the stream (according to [compare], which must + * be a [Comparator]). + * + * If [compare] is omitted, it defaults to [Comparable.compare]. + */ + Future max([int compare(T a, T b)]) { + if (compare == null) compare = Comparable.compare; + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + T max = null; + subscription = this.listen( + (T value) { + max = value; + subscription.onData((T value) { + if (compare(max, value) < 0) max = value; + }); + }, + onError: future._setError, + onDone: () { + future._setValue(max); + }, + unsubscribeOnError: true + ); + return future; + } + + /** Reports whether this stream contains any elements. */ + Future get isEmpty { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (_) { + subscription.cancel(); + future._setValue(false); + }, + onError: future._setError, + onDone: () { + future._setValue(true); + }, + unsubscribeOnError: true); + return future; + } + + /** Collect the data of this stream in a [List]. */ + Future> toList() { + List result = []; + _FutureImpl> future = new _FutureImpl>(); + this.listen( + (T data) { + result.add(data); + }, + onError: future._setError, + onDone: () { + future._setValue(result); + }, + unsubscribeOnError: true); + return future; + } + + /** Collect the data of this stream in a [Set]. */ + Future> toSet() { + Set result = new Set(); + _FutureImpl> future = new _FutureImpl>(); + this.listen( + (T data) { + result.add(data); + }, + onError: future._setError, + onDone: () { + future._setValue(result); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Provide at most the first [n] values of this stream. + * + * Forwards the first [n] data events of this stream, and all error + * events, to the returned stream, and ends with a done event. + * + * If this stream produces fewer than [count] values before it's done, + * so will the returned stream. + */ + Stream take(int count) { + return this.transform(new TakeStream(count)); + } + + /** + * Forwards data events while [test] is successful. + * + * The returned stream provides the same events as this stream as long + * as [test] returns [:true:] for the event data. The stream is done + * when either this stream is done, or when this stream first provides + * a value that [test] doesn't accept. + */ + Stream takeWhile(bool test(T value)) { + return this.transform(new TakeWhileStream(test)); + } + + /** + * Skips the first [count] data events from this stream. + */ + Stream skip(int count) { + return this.transform(new SkipStream(count)); + } + + /** + * Skip data events from this stream while they are matched by [test]. + * + * Error and done events are provided by the returned stream unmodified. + * + * Starting with the first data event where [test] returns true for the + * event data, the returned stream will have the same events as this stream. + */ + Stream skipWhile(bool test(T value)) { + return this.transform(new SkipWhileStream(test)); + } + + /** + * Skip data events if they are equal to the previous data event. + * + * The returned stream provides the same events as this stream, except + * that it never provides two consequtive data events that are equal. + * + * Equality is determined by the provided [equals] method. If that is + * omitted, the '==' operator on the last provided data element is used. + */ + Stream distinct([bool equals(T previous, T next)]) { + return this.transform(new DistinctStream(equals)); + } + + /** + * Returns the first element. + * + * If [this] is empty throws a [StateError]. Otherwise this method is + * equivalent to [:this.elementAt(0):] + */ + Future get first { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (T value) { + future._setValue(value); + subscription.cancel(); + return; + }, + onError: future._setError, + onDone: () { + future._setError(new AsyncError(new StateError("No elements"))); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Returns the last element. + * + * If [this] is empty throws a [StateError]. + */ + Future get last { + _FutureImpl future = new _FutureImpl(); + T result = null; + bool foundResult = false; + StreamSubscription subscription; + subscription = this.listen( + (T value) { + foundResult = true; + result = value; + }, + onError: future._setError, + onDone: () { + if (foundResult) { + future._setValue(result); + return; + } + future._setError(new AsyncError(new StateError("No elements"))); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Returns the single element. + * + * If [this] is empty or has more than one element throws a [StateError]. + */ + Future get single { + _FutureImpl future = new _FutureImpl(); + T result = null; + bool foundResult = false; + StreamSubscription subscription; + subscription = this.listen( + (T value) { + if (foundResult) { + // This is the second element we get. + Error error = new StateError("More than one element"); + future._setError(new AsyncError(error)); + subscription.cancel(); + return; + } + foundResult = true; + result = value; + }, + onError: future._setError, + onDone: () { + if (foundResult) { + future._setValue(result); + return; + } + future._setError(new AsyncError(new StateError("No elements"))); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Find the first element of this stream matching [test]. + * + * Returns a future that is filled with the first element of this stream + * that [test] returns true for. + * + * If no such element is found before this stream is done, and a + * [defaultValue] function is provided, the result of calling [defaultValue] + * becomes the value of the future. + * + * If an error occurs, or if this stream ends without finding a match and + * with no [defaultValue] function provided, the future will receive an + * error. + */ + Future firstMatching(bool test(T value), {T defaultValue()}) { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (T value) { + bool matches; + try { + matches = (true == test(value)); + } catch (e, s) { + future._setError(new AsyncError(e, s)); + subscription.cancel(); + return; + } + if (matches) { + future._setValue(value); + subscription.cancel(); + } + }, + onError: future._setError, + onDone: () { + if (defaultValue != null) { + T value; + try { + value = defaultValue(); + } catch (e, s) { + future._setError(new AsyncError(e, s)); + return; + } + future._setValue(value); + return; + } + future._setError( + new AsyncError(new StateError("firstMatch ended without match"))); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Finds the last element in this stream matching [test]. + * + * As [firstMatching], except that the last matching element is found. + * That means that the result cannot be provided before this stream + * is done. + */ + Future lastMatching(bool test(T value), {T defaultValue()}) { + _FutureImpl future = new _FutureImpl(); + T result = null; + bool foundResult = false; + StreamSubscription subscription; + subscription = this.listen( + (T value) { + bool matches; + try { + matches = (true == test(value)); + } catch (e, s) { + future._setError(new AsyncError(e, s)); + subscription.cancel(); + return; + } + if (matches) { + foundResult = true; + result = value; + } + }, + onError: future._setError, + onDone: () { + if (foundResult) { + future._setValue(result); + return; + } + if (defaultValue != null) { + T value; + try { + value = defaultValue(); + } catch (e, s) { + future._setError(new AsyncError(e, s)); + return; + } + future._setValue(value); + return; + } + future._setError( + new AsyncError(new StateError("lastMatch ended without match"))); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Finds the single element in this stream matching [test]. + * + * Like [lastMatch], except that it is an error if more than one + * matching element occurs in the stream. + */ + Future singleMatching(bool test(T value)) { + _FutureImpl future = new _FutureImpl(); + T result = null; + bool foundResult = false; + StreamSubscription subscription; + subscription = this.listen( + (T value) { + bool matches; + try { + matches = (true == test(value)); + } catch (e, s) { + future._setError(new AsyncError(e, s)); + subscription.cancel(); + return; + } + if (matches) { + if (foundResult) { + future._setError(new AsyncError( + new StateError('Multiple matches for "single"'))); + subscription.cancel(); + return; + } + foundResult = true; + result = value; + } + }, + onError: future._setError, + onDone: () { + if (foundResult) { + future._setValue(result); + return; + } + future._setError( + new AsyncError(new StateError("single ended without match"))); + }, + unsubscribeOnError: true); + return future; + } + + /** + * Returns the value of the [index]th data event of this stream. + * + * If an error event occurs, the future will end with this error. + * + * If this stream provides fewer than [index] elements before closing, + * an error is reported. + */ + Future elementAt(int index) { + _FutureImpl future = new _FutureImpl(); + StreamSubscription subscription; + subscription = this.listen( + (T value) { + if (index == 0) { + future._setValue(value); + subscription.cancel(); + return; + } + index -= 1; + }, + onError: future._setError, + onDone: () { + future._setError(new AsyncError( + new StateError("Not enough elements for elementAt"))); + }, + unsubscribeOnError: true); + return future; + } +} + +/** + * A control object for the subscription on a [Stream]. + * + * When you subscribe on a [Stream] using [Stream.subscribe], + * a [StreamSubscription] object is returned. This object + * is used to later unsubscribe again, or to temporarily pause + * the stream's events. + */ +abstract class StreamSubscription { + /** + * Cancels this subscription. It will no longer receive events. + * + * If an event is currently firing, this unsubscription will only + * take effect after all subscribers have received the current event. + */ + void cancel(); + + /** Set or override the data event handler of this subscription. */ + void onData(void handleData(T data)); + + /** Set or override the error event handler of this subscription. */ + void onError(void handleError(AsyncError error)); + + /** Set or override the done event handler of this subscription. */ + void onDone(void handleDone()); + + /** + * Request that the stream pauses events until further notice. + * + * If [resumeSignal] is provided, the stream will undo the pause + * when the signal completes. + * A call to [resume] will also undo a pause. + * + * If the subscription is paused more than once, an equal number + * of resumes must be performed to resume the stream. + */ + void pause([Signal resumeSignal]); + + /** + * Resume after a pause. + */ + void resume(); +} + + +/** + * An interface that abstracts sending events into a [Stream]. + */ +abstract class StreamSink implements Sink { + void add(T event); + /** Signal an async error to the receivers of this sink's values. */ + void signalError(AsyncError errorEvent); + void close(); +} + +/** [Stream] wrapper that only exposes the [Stream] interface. */ +class StreamView extends Stream { + Stream _stream; + + StreamView(this._stream); + + StreamSubscription listen(void onData(T value), + { void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError }) { + return _stream.listen(onData, onError: onError, onDone: onDone, + unsubscribeOnError: unsubscribeOnError); + } +} + +/** + * [StreamSink] wrapper that only exposes the [StreamSink] interface. + */ +class StreamSinkView implements StreamSink { + final StreamSink _sink; + + StreamSinkView(this._sink); + + void add(T value) { _sink.add(value); } + void signalError(AsyncError error) { _sink.signalError(error); } + void close() { _sink.close(); } +} + + +/** + * The target of a [Stream.pipe] call. + * + * The [Stream.pipe] call will pass itself to this object, and then return + * the resulting [Future]. The pipe should complete the future when it's + * done. + */ +abstract class StreamConsumer { + Future consume(Stream stream); +} + +/** + * The target of a [Stream.transform] call. + * + * The [Stream.transform] call will pass itself to this object and then return + * the resulting stream. + */ +abstract class StreamTransformer { + /** + * Create a [StreamTransformer] that delegates events to the given functions. + * + * If a parameter is omitted, a default handler is used that forwards the + * event directly to the sink. + * + * Pauses on the are forwarded to the input stream as well. + */ + factory StreamTransformer.from({ + void onData(S data, StreamSink sink), + void onError(AsyncError error, StreamSink sink), + void onDone(StreamSink sink)}) = _StreamTransformerFunctionWrapper; + + Stream bind(Stream stream); +} + + +// TODO(lrn): Remove this class. +/** + * A base class for configuration objects for [TransformStream]. + * + * A default implementation forwards all incoming events to the output sink. + */ +abstract class _StreamTransformer implements StreamTransformer { + const _StreamTransformer(); + + Stream bind(Stream input) { + return input.transform(new TransformStream(this)); + } + + /** + * Handle an incoming data event. + */ + void handleData(S data, StreamSink sink) { + var outData = data; + return sink.add(outData); + } + + /** + * Handle an incoming error event. + */ + void handleError(AsyncError error, StreamSink sink) { + sink.signalError(error); + } + + /** + * Handle an incoming done event. + */ + void handleDone(StreamSink sink) { + sink.close(); + } +} diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart new file mode 100644 index 00000000000..a60ca8167ab --- /dev/null +++ b/sdk/lib/async/stream_controller.dart @@ -0,0 +1,156 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +// ------------------------------------------------------------------- +// Default implementation of a stream with a controller for adding +// events to the stream. +// ------------------------------------------------------------------- + +/** + * A controller and the stream it controls. + * + * This controller allows sending data, error and done events on + * its [stream]. + * This class can be used to create a simple stream that others + * can listen on, and to push events to that stream. + * For more specialized streams, the [createStream] method can be + * overridden to return a specialization of [ControllerStream], and + * other public methods can be overridden too (but it's recommended + * that the overriding method calls its super method). + * + * A [StreamController] may have zero or more subscribers. + * + * If it has subscribers, it may also be paused by any number of its + * subscribers. When paused, all incoming events are queued. It is the + * responsibility of the user of this stream to prevent incoming events when + * the controller is paused. When there are no pausing subscriptions left, + * either due to them resuming, or due to the pausing subscriptions + * unsubscribing, events are resumed. + * + * When "close" is invoked (but not necessarily when the done event is fired, + * depending on pause state) the stream controller is closed. + * When the done event is fired to a subscriber, the subscriber is automatically + * unsubscribed. + */ +class StreamController extends Stream implements StreamSink { + _StreamImpl _stream; + Stream get stream => _stream; + + /** + * A controller with a [stream] that supports multiple subscribers. + */ + StreamController() { + _stream = new _MultiControllerStream(onSubscriptionStateChange, + onPauseStateChange); + } + /** + * A controller with a [stream] that supports only one single subscriber. + * The controller will buffer all incoming events until the subscriber is + * registered. + */ + StreamController.singleSubscription() { + _stream = new _SingleControllerStream(onSubscriptionStateChange, + onPauseStateChange); + } + + StreamSubscription listen(void onData(T data), + { void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError}) { + return _stream.listen(onData, + onError: onError, + onDone: onDone, + unsubscribeOnError: unsubscribeOnError); + } + + /** + * Returns a view of this object that only exposes the [StreamSink] interface. + */ + StreamSink get sink => new StreamSinkView(this); + + /** Whether one or more active subscribers have requested a pause. */ + bool get isPaused => _stream._isPaused; + + /** Whether there are currently any subscribers on this [Stream]. */ + bool get hasSubscribers => _stream._hasSubscribers; + + /** + * Send or queue a data event. + */ + Signal add(T value) => _stream._add(value); + + /** + * Send or enqueue an error event. + * + * If a subscription has requested to be unsubscribed on errors, + * it will be unsubscribed after receiving this event. + */ + void signalError(AsyncError error) { _stream._signalError(error); } + + /** + * Send or enqueue a "done" message. + * + * The "done" message should be sent at most once by a stream, and it + * should be the last message sent. + */ + void close() { _stream._close(); } + + /** + * Called when the first subscriber requests a pause or the last a resume. + * + * Read [isPaused] to see the new state. + */ + void onPauseStateChange() {} + + /** + * Called when the first listener subscribes or the last unsubscribes. + * + * Read [hasSubscribers] to see what the new state is. + */ + void onSubscriptionStateChange() {} + + void forEachSubscriber(void action(_StreamSubscriptionImpl subscription)) { + _stream._forEachSubscriber(() { + try { + action(); + } catch (e, s) { + new AsyncError(e, s).throwDelayed(); + } + }); + } +} + +typedef void _NotificationHandler(); + +class _MultiControllerStream extends _MultiStreamImpl { + _NotificationHandler _subscriptionHandler; + _NotificationHandler _pauseHandler; + + _MultiControllerStream(this._subscriptionHandler, this._pauseHandler); + + void _onSubscriptionStateChange() { + _subscriptionHandler(); + } + + void _onPauseStateChange() { + _pauseHandler(); + } +} + +class _SingleControllerStream extends _SingleStreamImpl { + _NotificationHandler _subscriptionHandler; + _NotificationHandler _pauseHandler; + + _SingleControllerStream(this._subscriptionHandler, this._pauseHandler); + + void _onSubscriptionStateChange() { + _subscriptionHandler(); + } + + void _onPauseStateChange() { + _pauseHandler(); + } +} diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart new file mode 100644 index 00000000000..f99dc83ba23 --- /dev/null +++ b/sdk/lib/async/stream_impl.dart @@ -0,0 +1,1017 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +// States shared by single/multi stream implementations. + +/// Initial and default state where the stream can receive and send events. +const int _STREAM_OPEN = 0; +/// The stream has received a request to complete, but hasn't done so yet. +/// No further events can be aded to the stream. +const int _STREAM_CLOSED = 1; +/// The stream has completed and will no longer receive or send events. +/// Also counts as closed. The stream must not be paused when it's completed. +/// Always used in conjunction with [_STREAM_CLOSED]. +const int _STREAM_COMPLETE = 2; +/// Bit that alternates between events, and listeners are updated to the +/// current value when they are notified of the event. +const int _STREAM_EVENT_ID = 4; +const int _STREAM_EVENT_ID_SHIFT = 2; +/// Bit set while firing and clear while not. +const int _STREAM_FIRING = 8; +/// The count of times a stream has paused is stored in the +/// state, shifted by this amount. +const int _STREAM_PAUSE_COUNT_SHIFT = 4; + +// States for listeners. + +/// The listener is currently not subscribed to its source stream. +const int _LISTENER_UNSUBSCRIBED = 0; +/// The listener is actively subscribed to its source stream. +const int _LISTENER_SUBSCRIBED = 1; +/// The listener is subscribed until it has been notified of the current event. +/// This flag bit is always used in conjuction with [_LISTENER_SUBSCRIBED]. +const int _LISTENER_PENDING_UNSUBSCRIBE = 2; +/// Bit that contains the last sent event's "id bit". +const int _LISTENER_EVENT_ID = 4; +const int _LISTENER_EVENT_ID_SHIFT = 2; +/// The count of times a listener has paused is stored in the +/// state, shifted by this amount. +const int _LISTENER_PAUSE_COUNT_SHIFT = 3; + + +// ------------------------------------------------------------------- +// Common base class for single and multi-subscription streams. +// ------------------------------------------------------------------- +abstract class _StreamImpl extends Stream { + /** Current state of the stream. */ + int _state = _STREAM_OPEN; + + /** + * List of pending events. + * + * If events are added to the stream (using [_add], [_signalError] or [_done]) + * while the stream is paused, or while another event is firing, events will + * stored here. + * Also supports scheduling the events for later execution. + */ + _StreamImplEvents _pendingEvents; + + // ------------------------------------------------------------------ + // Stream interface. + + StreamSubscription listen(void onData(T data), + { void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError }) { + if (_isComplete) { + return new _DoneSubscription(onDone); + } + if (onData == null) onData = _nullDataHandler; + if (onError == null) onError = _nullErrorHandler; + if (onDone == null) onDone = _nullDoneHandler; + unsubscribeOnError = identical(true, unsubscribeOnError); + _StreamListener subscription = + _createSubscription(onData, onError, onDone, unsubscribeOnError); + _addListener(subscription); + return subscription; + } + + // ------------------------------------------------------------------ + // StreamSink interface-like methods for sending events into the stream. + // It's the responsibility of the caller to ensure that the stream is not + // paused when adding events. If the stream is paused, the events will be + // queued, but it's better to not send events at all. + + /** + * Send or queue a data event. + */ + void _add(T value) { + if (_isClosed) throw new StateError("Sending on closed stream"); + if (!_canFireEvent) { + _addPendingEvent(new _DelayedData(value)); + return; + } + _sendData(value); + _handlePendingEvents(); + } + + /** + * Send or enqueue an error event. + * + * If a subscription has requested to be unsubscribed on errors, + * it will be unsubscribed after receiving this event. + */ + void _signalError(AsyncError error) { + if (_isClosed) throw new StateError("Sending on closed stream"); + if (!_canFireEvent) { + _addPendingEvent(new _DelayedError(error)); + return; + } + _sendError(error); + _handlePendingEvents(); + } + + /** + * Send or enqueue a "done" message. + * + * The "done" message should be sent at most once by a stream, and it + * should be the last message sent. + */ + void _close() { + if (_isClosed) throw new StateError("Sending on closed stream"); + _state |= _STREAM_CLOSED; + if (!_canFireEvent) { + // You can't enqueue an event after the Done, so make it const. + _addPendingEvent(const _DelayedDone()); + return; + } + _sendDone(); + assert(!_hasPendingEvent); + } + + // ------------------------------------------------------------------- + // Internal implementation. + + // State prediates. + + /** Whether the stream has been closed (a done event requested). */ + bool get _isClosed => (_state & _STREAM_CLOSED) != 0; + + /** Whether the stream is completed. */ + bool get _isComplete => (_state & _STREAM_COMPLETE) != 0; + + /** Whether one or more active subscribers have requested a pause. */ + bool get _isPaused => _state >= (1 << _STREAM_PAUSE_COUNT_SHIFT); + + /** Check whether the pending event queue is non-empty */ + bool get _hasPendingEvent => + _pendingEvents != null && !_pendingEvents.isEmpty; + + /** Whether we are currently firing an event. */ + bool get _isFiring => (_state & _STREAM_FIRING) != 0; + + int get _currentEventIdBit => + (_state & _STREAM_EVENT_ID ) >> _STREAM_EVENT_ID_SHIFT; + + /** Whether there is currently a subscriber on this [Stream]. */ + bool get _hasSubscribers; + + /** Whether the stream can fire a new event. */ + bool get _canFireEvent => !_isFiring && !_isPaused && !_hasPendingEvent; + + // State modification. + + /** Record an increases in the number of times the listener has paused. */ + void _incrementPauseCount(_StreamListener listener) { + listener._incrementPauseCount(); + _updatePauseCount(1); + } + + /** Record a decrease in the number of times the listener has paused. */ + void _decrementPauseCount(_StreamListener listener) { + assert(_isPaused); + listener._decrementPauseCount(); + _updatePauseCount(-1); + } + + /** Update the stream's own pause count only. */ + void _updatePauseCount(int by) { + _state += by << _STREAM_PAUSE_COUNT_SHIFT; + assert(_state >= 0); + } + + void _setClosed() { + assert(!_isClosed); + _state |= _STREAM_CLOSED; + } + + void _setComplete() { + assert(_isClosed); + _state = _state |_STREAM_COMPLETE; + } + + void _startFiring() { + assert(!_isFiring); + // This sets the _STREAM_FIRING bit and toggles the _STREAM_EVENT_ID + // bit. All current subscribers will now have a _LISTENER_EVENT_ID + // that doesn't match _STREAM_EVENT_ID, and they will receive the + // event being fired. + _state ^= _STREAM_FIRING | _STREAM_EVENT_ID; + } + + void _endFiring() { + assert(_isFiring); + _state ^= _STREAM_FIRING; + } + + /** + * Record that a listener wants a pause from events. + * + * This methods is called from [_StreamListener.pause()]. + * Subclasses can override this method, along with [isPaused] and + * [createSubscription], if they want to do a different handling of paused + * subscriptions, e.g., a filtering stream pausing its own source if all its + * subscribers are paused. + */ + void _pause(_StreamListener listener, Signal resumeSignal) { + assert(identical(listener._source, this)); + if (!listener._isSubscribed) { + throw new StateError("Subscription has been canceled."); + } + assert(!_isComplete); // There can be no subscribers when complete. + bool wasPaused = _isPaused; + _incrementPauseCount(listener); + if (resumeSignal != null) { + resumeSignal.then(() { this._resume(listener, true); }); + } + if (!wasPaused) { + _onPauseStateChange(); + } + } + + /** Stops pausing due to one request from the given listener. */ + void _resume(_StreamListener listener, bool fromEvent) { + if (!listener.isPaused) return; + assert(listener._isSubscribed); + assert(_isPaused); + _decrementPauseCount(listener); + if (!_isPaused) { + _onPauseStateChange(); + if (_hasPendingEvent) { + // If we can fire events now, fire any pending events right away. + if (fromEvent && !_isFiring) { + _handlePendingEvents(); + } else { + _pendingEvents.schedule(this); + } + } + } + } + + /** Create a subscription object. Called by [subcribe]. */ + _StreamSubscriptionImpl _createSubscription( + void onData(T data), + void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError); + + /** + * Adds a listener to this stream. + */ + void _addListener(_StreamSubscriptionImpl subscription); + + /** + * Handle a cancel requested from a [_StreamSubscriptionImpl]. + * + * This method is called from [_StreamSubscriptionImpl.cancel]. + * + * If an event is currently firing, the cancel is delayed + * until after the subscribers have received the event. + */ + void _cancel(_StreamSubscriptionImpl subscriber); + + /** + * Iterate over all current subscribers and perform an action on each. + * + * Subscribers added during the iteration will not be visited. + * Subscribers unsubscribed during the iteration will only be removed + * after they have been acted on. + * + * Any change in the pause state is only reported after all subscribers have + * received the event. + * + * The [action] must not throw, or the controller will be left in an + * invalid state. + * + * This method must not be called while [isFiring] is true. + */ + void _forEachSubscriber(void action(_StreamSubscriptionImpl subscription)); + + /** + * Called when the first subscriber requests a pause or the last a resume. + * + * Read [isPaused] to see the new state. + */ + void _onPauseStateChange() {} + + /** + * Called when the first listener subscribes or the last unsubscribes. + * + * Read [hasSubscribers] to see what the new state is. + */ + void _onSubscriptionStateChange() {} + + /** Add a pending event at the end of the pending event queue. */ + void _addPendingEvent(_DelayedEvent event) { + if (_pendingEvents == null) _pendingEvents = new _StreamImplEvents(); + _pendingEvents.add(event); + } + + /** Fire any pending events until the pending event queue. */ + void _handlePendingEvents() { + _StreamImplEvents events = _pendingEvents; + if (events == null) return; + while (!events.isEmpty && !_isPaused) { + events.removeFirst().perform(this); + } + } + + /** + * Send a data event directly to each subscriber. + */ + _sendData(T value) { + assert(!_isPaused); + assert(!_isComplete); + _forEachSubscriber((subscriber) { + try { + subscriber._sendData(value); + } catch (e, s) { + new AsyncError(e, s).throwDelayed(); + } + }); + } + + /** + * Sends an error event directly to each subscriber. + */ + void _sendError(AsyncError error) { + assert(!_isPaused); + assert(!_isComplete); + _forEachSubscriber((subscriber) { + try { + subscriber._sendError(error); + } catch (e, s) { + new AsyncError.withCause(e, s, error).throwDelayed(); + } + }); + } + + /** + * Sends the "done" message directly to each subscriber. + * This automatically stops further subscription and + * unsubscribes all subscribers. + */ + void _sendDone() { + assert(!_isPaused); + assert(_isClosed); + _setComplete(); + if (!_hasSubscribers) return; + _forEachSubscriber((subscriber) { + _cancel(subscriber); + try { + subscriber._sendDone(); + } catch (e, s) { + new AsyncError(e, s).throwDelayed(); + } + }); + assert(!_hasSubscribers); + _onSubscriptionStateChange(); + } +} + +// ------------------------------------------------------------------- +// Default implementation of a stream with a single subscriber. +// ------------------------------------------------------------------- +/** + * Default implementation of stream capable of sending events to one subscriber. + * + * Any class needing to implement [Stream] can either directly extend this + * class, or extend [Stream] and delegate the subscribe method to an instance + * of this class. + * + * The only public methods are those of [Stream], so instances of + * [_SingleStreamImpl] can be returned directly as a [Stream] without exposing + * internal functionality. + * + * The [StreamController] is a public facing version of this class, with + * some methods made public. + * + * The user interface of [_SingleStreamImpl] are the following methods: + * * [_add]: Add a data event to the stream. + * * [_signalError]: Add an error event to the stream. + * * [_close]: Request to close the stream. + * * [_onSubscriberStateChange]: Called when receiving the first subscriber or + * when losing the last subscriber. + * * [_onPauseStateChange]: Called when entering or leaving paused mode. + * * [_hasSubscribers]: Test whether there are currently any subscribers. + * * [_isPaused]: Test whether the stream is currently paused. + * The user should not add new events while the stream is paused, but if it + * happens anyway, the stream will enqueue the events just as when new events + * arrive while still firing an old event. + */ +class _SingleStreamImpl extends _StreamImpl { + _StreamSubscriptionImpl _subscriber = null; + + /** Whether one or more active subscribers have requested a pause. */ + bool get _isPaused => !_hasSubscribers || super._isPaused; + + /** Whether there is currently a subscriber on this [Stream]. */ + bool get _hasSubscribers => _subscriber != null; + + // ------------------------------------------------------------------- + // Internal implementation. + + /** + * Create the new subscription object. + */ + _StreamSubscriptionImpl _createSubscription( + void onData(T data), + void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError) { + return new _StreamSubscriptionImpl( + this, onData, onError, onDone, unsubscribeOnError); + } + + void _addListener(_StreamSubscriptionImpl subscription) { + if (_hasSubscribers) { + throw new StateError("Stream has already subscriber."); + } + _subscriber = subscription; + subscription._setSubscribed(0); + _onSubscriptionStateChange(); + // TODO(floitsch): Should this be delayed? + _handlePendingEvents(); + } + + /** + * Handle a cancel requested from a [_StreamSubscriptionImpl]. + * + * This method is called from [_StreamSubscriptionImpl.cancel]. + * + * If an event is currently firing, the cancel is delayed + * until after the subscriber has received the event. + */ + void _cancel(_StreamSubscriptionImpl subscriber) { + assert(identical(subscriber._source, this)); + // We allow unsubscribing the currently firing subscription during + // the event firing, because it is indistinguishable from delaying it since + // that event has already received the event. + if (!identical(_subscriber, subscriber)) { + // You may unsubscribe more than once, only the first one counts. + return; + } + _subscriber = null; + int timesPaused = subscriber._setUnsubscribed(); + _updatePauseCount(-timesPaused); + if (timesPaused > 0) { + _onPauseStateChange(); + } + _onSubscriptionStateChange(); + } + + void _forEachSubscriber( + void action(_StreamSubscriptionImpl subscription)) { + _StreamSubscriptionImpl subscription = _subscriber; + assert(subscription != null); + _startFiring(); + action(subscription); + _endFiring(); + } +} + +// ------------------------------------------------------------------- +// Default implementation of a stream with subscribers. +// ------------------------------------------------------------------- + +/** + * Default implementation of stream capable of sending events to subscribers. + * + * Any class needing to implement [Stream] can either directly extend this + * class, or extend [Stream] and delegate the subscribe method to an instance + * of this class. + * + * The only public methods are those of [Stream], so instances of + * [_MultiStreamImpl] can be returned directly as a [Stream] without exposing + * internal functionality. + * + * The [StreamController] is a public facing version of this class, with + * some methods made public. + * + * The user interface of [_MultiStreamImpl] are the following methods: + * * [_add]: Add a data event to the stream. + * * [_signalError]: Add an error event to the stream. + * * [_close]: Request to close the stream. + * * [_onSubscriptionStateChange]: Called when receiving the first subscriber or + * when losing the last subscriber. + * * [_onPauseStateChange]: Called when entering or leaving paused mode. + * * [_hasSubscribers]: Test whether there are currently any subscribers. + * * [_isPaused]: Test whether the stream is currently paused. + * The user should not add new events while the stream is paused, but if it + * happens anyway, the stream will enqueue the events just as when new events + * arrive while still firing an old event. + */ +class _MultiStreamImpl extends _StreamImpl + implements _InternalLinkList { + // Link list implementation (mixin when possible). + _InternalLink _nextLink; + _InternalLink _previousLink; + + _MultiStreamImpl() { + _nextLink = _previousLink = this; + } + + // ------------------------------------------------------------------ + // Helper functions that can be overridden in subclasses. + + /** Whether there are currently any subscribers on this [Stream]. */ + bool get _hasSubscribers => !_InternalLinkList.isEmpty(this); + + /** + * Create the new subscription object. + */ + _StreamListener _createSubscription( + void onData(T data), + void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError) { + return new _StreamSubscriptionImpl( + this, onData, onError, onDone, unsubscribeOnError); + } + + // ------------------------------------------------------------------- + // Internal implementation. + + /** + * Iterate over all current subscribers and perform an action on each. + * + * The set of subscribers cannot be modified during this iteration. + * All attempts to add or unsubscribe subscribers will be delayed until + * after the iteration is complete. + * + * The [action] must not throw, or the controller will be left in an + * invalid state. + * + * This method must not be called while [isFiring] is true. + */ + void _forEachSubscriber( + void action(_StreamListener subscription)) { + assert(!_isFiring); + if (!_hasSubscribers) return; + _startFiring(); + _InternalLink cursor = this._nextLink; + while (!identical(cursor, this)) { + _StreamListener current = cursor; + if (current._needsEvent(_currentEventIdBit)) { + action(current); + // Marks as having received the event. + current._toggleEventReceived(); + } + cursor = current._nextLink; + if (current._isPendingUnsubscribe) { + _removeListener(current); + } + } + _endFiring(); + if (_isPaused) _onPauseStateChange(); + if (!_hasSubscribers) _onSubscriptionStateChange(); + } + + void _addListener(_StreamListener listener) { + listener._setSubscribed(_currentEventIdBit); + bool firstSubscriber = !_hasSubscribers; + _InternalLinkList.add(this, listener); + if (firstSubscriber) { + _onSubscriptionStateChange(); + } + } + + /** + * Handle a cancel requested from a [_StreamListener]. + * + * This method is called from [_StreamListener.cancel]. + * + * If an event is currently firing, the cancel is delayed + * until after the subscribers have received the event. + */ + void _cancel(_StreamListener listener) { + assert(identical(listener._source, this)); + if (_InternalLink.isUnlinked(listener)) { + // You may unsubscribe more than once, only the first one counts. + return; + } + if (_isFiring) { + if (listener._needsEvent(_currentEventIdBit)) { + assert(listener._isSubscribed); + listener._setPendingUnsubscribe(); + } else { + // The listener has been notified of the event (or don't need to, + // if it's still pending subscription) so it's safe to remove it. + _removeListener(listener); + } + // Pause and subscription state changes are reported when we end + // firing. + } else { + bool wasPaused = _isPaused; + _removeListener(listener); + if (wasPaused != _isPaused) _onPauseStateChange(); + if (!_hasSubscribers) _onSubscriptionStateChange(); + } + } + + /** + * Removes a listener from this stream and cancels its pauses. + * + * This is a low-level action that doesn't call [_onSubscriptionStateChange]. + * or [_onPauseStateChange]. + */ + void _removeListener(_StreamListener listener) { + int pauseCount = listener._setUnsubscribed(); + _updatePauseCount(-pauseCount); + _InternalLinkList.remove(listener); + } +} + +/** + * The subscription class that the [StreamController] uses. + * + * The [StreamController.createSubscription] method should + * create an object of this type, or another subclass of [_StreamListener]. + * A subclass of [StreamController] can specify which subclass + * of [_StreamSubscriptionImpl] it uses by overriding + * [StreamController.createSubscription]. + * + * The subscription is in one of three states: + * * Subscribed. + * * Paused-and-subscribed. + * * Unsubscribed. + * Unsubscribing also unpauses. + */ +class _StreamSubscriptionImpl extends _StreamListener + implements StreamSubscription { + final bool _unsubscribeOnError; + _DataHandler _onData; + _ErrorHandler _onError; + _DoneHandler _onDone; + _StreamSubscriptionImpl(_StreamImpl source, + this._onData, + this._onError, + this._onDone, + this._unsubscribeOnError) : super(source); + + void onData(void handleData(T event)) { + if (handleData == null) handleData = _nullDataHandler; + _onData = handleData; + } + + void onError(void handleError(AsyncError error)) { + if (handleError == null) handleError = _nullErrorHandler; + _onError = handleError; + } + + void onDone(void handleDone()) { + if (handleDone == null) handleDone = _nullDoneHandler; + _onDone = handleDone; + } + + void _sendData(T data) { + _onData(data); + } + + void _sendError(AsyncError error) { + _onError(error); + if (_unsubscribeOnError) _source._cancel(this); + } + + void _sendDone() { + _onDone(); + } + + void cancel() { + _source._cancel(this); + } + + void pause([Signal resumeSignal]) { + _source._pause(this, resumeSignal); + } + + void resume() { + if (!isPaused) { + throw new StateError("Resuming unpaused subscription"); + } + _source._resume(this, false); + } +} + +// Internal helpers. + +// Types of the different handlers on a stream. Types used to type fields. +typedef void _DataHandler(T value); +typedef void _ErrorHandler(AsyncError error); +typedef void _DoneHandler(); + + +/** Default data handler, does nothing. */ +void _nullDataHandler(var value) {} + +/** Default error handler, reports the error to the global handler. */ +void _nullErrorHandler(AsyncError error) { + error.throwDelayed(); +} + +/** Default done handler, does nothing. */ +void _nullDoneHandler() {} + + +/** A delayed event on a stream implementation. */ +abstract class _DelayedEvent { + /** Added as a linked list on the [StreamController]. */ + _DelayedEvent next; + /** Execute the delayed event on the [StreamController]. */ + void perform(_StreamImpl stream); +} + +/** A delayed data event. */ +class _DelayedData extends _DelayedEvent{ + T value; + _DelayedData(this.value); + void perform(_StreamImpl stream) { + stream._sendData(value); + } +} + +/** A delayed error event. */ +class _DelayedError extends _DelayedEvent { + AsyncError error; + _DelayedError(this.error); + void perform(_StreamImpl stream) { + stream._sendError(error); + } +} + +/** A delayed done event. */ +class _DelayedDone implements _DelayedEvent { + const _DelayedDone(); + void perform(_StreamImpl stream) { + stream._sendDone(); + } + + _DelayedEvent get next => null; + + void set next(_DelayedEvent _) { + throw new StateError("No events after a done."); + } +} + +/** + * Simple internal doubly-linked list implementation. + * + * In an internal linked list, the links are in the data objects themselves, + * instead of in a separate object. That means each element can be in at most + * one list at a time. + * + * All links are always members of an element cycle. At creation it's a + * singleton cycle. + */ +abstract class _InternalLink { + _InternalLink _nextLink; + _InternalLink _previousLink; + + _InternalLink() { + this._previousLink = this._nextLink = this; + } + + /* Removes a link from any list it may be part of, and links it to itself. */ + static void unlink(_InternalLink element) { + _InternalLink next = element._nextLink; + _InternalLink previous = element._previousLink; + next._previousLink = previous; + previous._nextLink = next; + element._nextLink = element._previousLink = element; + } + + /** Check whether an element is unattached to other elements. */ + static bool isUnlinked(_InternalLink element) { + return identical(element, element._nextLink); + } +} + +/** + * Marker interface for "list" links. + * + * An "InternalLinkList" is an abstraction on top of a link cycle, where the + * "list" object itself is not considered an element (it's just a header link + * created to avoid edge cases). + * An element is considered part of a list if it is in the list's cycle. + * There should never be more than one "list" object in a cycle. + */ +abstract class _InternalLinkList extends _InternalLink { + /** + * Adds an element to a list, just before the header link. + * + * This effectively adds it at the end of the list. + */ + static void add(_InternalLinkList list, _InternalLink element) { + if (!_InternalLink.isUnlinked(element)) _InternalLink.unlink(element); + _InternalLink listEnd = list._previousLink; + listEnd._nextLink = element; + list._previousLink = element; + element._previousLink = listEnd; + element._nextLink = list; + } + + /** Removes an element from its list. */ + static void remove(_InternalLink element) { + _InternalLink.unlink(element); + } + + /** Check whether a list contains no elements, only the header link. */ + static bool isEmpty(_InternalLinkList list) => _InternalLink.isUnlinked(list); + + /** Moves all elements from the list [other] to [list]. */ + static void addAll(_InternalLinkList list, _InternalLinkList other) { + if (isEmpty(other)) return; + _InternalLink listLast = list._previousLink; + _InternalLink otherNext = other._nextLink; + listLast._nextLink = otherNext; + otherNext._previousLink = listLast; + _InternalLink otherLast = other._previousLink; + list._previousLink = otherLast; + otherLast._nextLink = list; + // Clean up [other]. + other._nextLink = other._previousLink = other; + } +} + +abstract class _StreamListener extends _InternalLink { + final _StreamImpl _source; + int _state = _LISTENER_UNSUBSCRIBED; + + _StreamListener(this._source); + + bool get isPaused => _state >= (1 << _LISTENER_PAUSE_COUNT_SHIFT); + + bool get _isPendingUnsubscribe => + (_state & _LISTENER_PENDING_UNSUBSCRIBE) != 0; + + bool get _isSubscribed => (_state & _LISTENER_SUBSCRIBED) != 0; + + /** + * Whether the listener still needs to receive the currently firing event. + * + * The currently firing event is identified by a single bit, which alternates + * between events. The [_state] contains the previously sent event's bit in + * the [_LISTENER_EVENT_ID] bit. If the two don't match, this listener + * still need the current event. + */ + bool _needsEvent(int currentEventIdBit) { + int lastEventIdBit = + (_state & _LISTENER_EVENT_ID) >> _LISTENER_EVENT_ID_SHIFT; + return lastEventIdBit != currentEventIdBit; + } + + /// If a subscriber's "firing bit" doesn't match the stream's firing bit, + /// we are currently firing an event and the subscriber still need to receive + /// the event. + void _toggleEventReceived() { + _state ^= _LISTENER_EVENT_ID; + } + + void _setSubscribed(int eventIdBit) { + assert(eventIdBit == 0 || eventIdBit == 1); + _state = _LISTENER_SUBSCRIBED | (eventIdBit << _LISTENER_EVENT_ID_SHIFT); + } + + void _setPendingUnsubscribe() { + assert(_isSubscribed); + _state |= _LISTENER_PENDING_UNSUBSCRIBE; + } + + /** + * Marks the listener as unsubscibed. + * + * Returns the number of unresumed pauses for the listener. + */ + int _setUnsubscribed() { + assert(_isSubscribed); + int timesPaused = _state >> _LISTENER_PAUSE_COUNT_SHIFT; + _state = _LISTENER_UNSUBSCRIBED; + return timesPaused; + } + + void _incrementPauseCount() { + _state += 1 << _LISTENER_PAUSE_COUNT_SHIFT; + } + + void _decrementPauseCount() { + assert(isPaused); + _state -= 1 << _LISTENER_PAUSE_COUNT_SHIFT; + } + + _sendData(T data); + _sendError(AsyncError error); + _sendDone(); +} + +/** Class holding pending events for a [_StreamImpl]. */ +class _StreamImplEvents { + /// Single linked list of [_DelayedEvent] objects. + _DelayedEvent firstPendingEvent = null; + /// Last element in the list of pending events. New events are added after it. + _DelayedEvent lastPendingEvent = null; + /** + * Timer set when pending events are scheduled for execution. + * + * When scheduling pending events for execution in a later cycle, the timer + * is stored here. If pending events are executed earlier than that, e.g., + * due to a second event in the current cycle, the timer is canceled again. + */ + Timer scheduleTimer = null; + + bool get isEmpty => lastPendingEvent == null; + + bool get isScheduled => scheduleTimer != null; + + void schedule(_StreamImpl stream) { + if (isScheduled) return; + scheduleTimer = new Timer(0, (_) { + scheduleTimer = null; + stream._handlePendingEvents(); + }); + } + + void cancelSchedule() { + assert(isScheduled); + scheduleTimer.cancel(); + scheduleTimer = null; + } + + void add(_DelayedEvent event) { + if (lastPendingEvent == null) { + firstPendingEvent = lastPendingEvent = event; + } else { + lastPendingEvent = lastPendingEvent.next = event; + } + } + + _DelayedEvent removeFirst() { + if (isScheduled) cancelSchedule(); + _DelayedEvent event = firstPendingEvent; + firstPendingEvent = event.next; + if (firstPendingEvent == null) { + lastPendingEvent = null; + } + return event; + } +} + + +class _DoneSubscription implements StreamSubscription { + _DoneHandler _handler; + Timer _timer; + int _pauseCount = 0; + + _DoneSubscription(this._handler) { + _delayDone(); + } + + void _delayDone() { + assert(_timer == null && _pauseCount == 0); + _timer = new Timer(0, (_) { + if (_handler != null) _handler(); + }); + } + + bool get _isComplete => _timer == null && _pauseCount == 0; + + void onData(void handleAction(T value)) {} + void onError(void handleError(StateError error)) {} + void onDone(void handleDone(T value)) { + _handler = handleDone; + } + + void pause([Signal signal]) { + if (_isComplete) { + throw new StateError("Subscription has been canceled."); + } + if (_timer != null) _timer.cancel(); + _pauseCount++; + } + + void resume() { + if (_isComplete) { + throw new StateError("Subscription has been canceled."); + } + if (_pauseCount == 0) return; + _pauseCount--; + if (_pauseCount == 0) { + _delayDone(); + } + } + + bool get isPaused => _pauseCount > 0; + + void cancel() { + if (_isComplete) { + throw new StateError("Subscription has been canceled."); + } + if (_timer != null) { + _timer.cancel(); + _timer = null; + } + _pauseCount = 0; + } +} diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart new file mode 100644 index 00000000000..e0da85d3793 --- /dev/null +++ b/sdk/lib/async/stream_pipe.dart @@ -0,0 +1,460 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +/** + * A pipe between two streams. + * + * The default pipe subscribes to the [source] and sends on the + * [stream]. + * + * The events are passed through the [_handleData], [_handleError] and + * [_handleDone] methods. Subclasses are supposed to add handling of some of + * the events by overriding these methods. + * + * This class is intended for internal use only. Users can use the [PipeStream] + * to configure similar behavior. + */ +abstract class _ForwardingStream extends _MultiStreamImpl + implements StreamTransformer { + Stream _source = null; + StreamSubscription _subscription = null; + + StreamController _createController() { + return new _BaseForwardingController(this); + } + + void _subscribeToSource() { + _subscription = _source.listen(this._handleData, + onError: this._handleError, + onDone: this._handleDone); + if (_isPaused) { + _subscription.pause(); + } + } + + Stream bind(Stream source) { + assert(_source == null); + _source = source; + if (_hasSubscribers) { + _subscribeToSource(); + } + return this; + } + + /** + * Subscribe or unsubscribe on [source] depending on whether + * [stream] has subscribers. + */ + void _onSubscriptionStateChange() { + if (_hasSubscribers) { + assert(_subscription == null); + if (_source != null) { + _subscribeToSource(); + } + } else { + if (_subscription != null) { + _subscription.cancel(); + _subscription = null; + } + } + } + + void _onPauseStateChange() { + if (_subscription == null) return; + if (isPaused) { + _subscription.pause(); + } else { + _subscription.resume(); + } + } + + void _handleData(S inputEvent) { + var outputEvent = inputEvent; + _add(outputEvent); + } + + void _handleError(AsyncError error) { + _signalError(error); + } + + void _handleDone() { + _close(); + } +} + + +// ------------------------------------------------------------------- +// Stream pipes used by the default Stream implementation. +// ------------------------------------------------------------------- + +typedef bool _Predicate(T value); + +class WhereStream extends _ForwardingStream { + final _Predicate _test; + + WhereStream(bool test(T value)) + : this._test = test; + + void _handleData(T inputEvent) { + bool satisfies; + try { + satisfies = _test(inputEvent); + } catch (e, s) { + _signalError(new AsyncError(e, s)); + return; + } + if (satisfies) { + _add(inputEvent); + } + } +} + + +typedef T _Transformation(S value); + +/** + * A stream pipe that converts data events before passing them on. + */ +class MapStream extends _ForwardingStream { + final _Transformation _transform; + + MapStream(T transform(S event)) + : this._transform = transform; + + void _handleData(S inputEvent) { + T outputEvent; + try { + outputEvent = _transform(inputEvent); + } catch (e, s) { + _signalError(new AsyncError(e, s)); + return; + } + _add(outputEvent); + } +} + +/** + * A stream pipe that converts data events before passing them on. + */ +class ExpandStream extends _ForwardingStream { + final _Transformation> _expand; + + ExpandStream(Iterable expand(S event)) + : this._expand = expand; + + void _handleData(S inputEvent) { + try { + for (T value in _expand(inputEvent)) { + _add(value); + } + } catch (e, s) { + // If either _expand or iterating the generated iterator throws, + // we abort the iteration. + _signalError(new AsyncError(e, s)); + } + } +} + + +typedef AsyncError _ErrorTransformation(AsyncError error); + +/** + * A stream pipe that converts or disposes error events + * before passing them on. + */ +class HandleErrorStream extends _ForwardingStream { + final _ErrorTransformation _transform; + + HandleErrorStream(AsyncError transform(AsyncError event)) + : this._transform = transform; + + void _handleError(AsyncError error) { + try { + error = _transform(error); + if (error == null) return; + } catch (e, s) { + error = new AsyncError.withCause(e, s, error); + } + _signalError(error); + } +} + + +typedef void _TransformDataHandler(S data, StreamSink sink); +typedef void _TransformErrorHandler(AsyncError data, StreamSink sink); +typedef void _TransformDoneHandler(StreamSink sink); + +/** + * A stream pipe that intercepts all events and can generate any event as + * output. + * + * Each incoming event on this [StreamSink] is passed to the corresponding + * provided event handler, along with a [StreamSink] linked to the [output] of + * this pipe. + * The handler can then decide which events to send to the output + */ +class PipeStream extends _ForwardingStream { + final _TransformDataHandler _onData; + final _TransformErrorHandler _onError; + final _TransformDoneHandler _onDone; + StreamSink _sink; + + PipeStream({void onData(S data, StreamSink sink), + void onError(AsyncError data, StreamSink sink), + void onDone(StreamSink sink)}) + : this._onData = (onData == null ? _defaultHandleData : onData), + this._onError = (onError == null ? _defaultHandleError : onError), + this._onDone = (onDone == null ? _defaultHandleDone : onDone) { + // Cache the sink wrapper to avoid creating a new one for each event. + this._sink = new _StreamImplSink(this); + } + + void _handleData(S data) { + try { + return _onData(data, _sink); + } catch (e, s) { + _signalError(new AsyncError(e, s)); + } + } + + void _handleError(AsyncError error) { + try { + _onError(error, _sink); + } catch (e, s) { + _signalError(new AsyncError.withCause(e, s, error)); + } + } + + void _handleDone() { + try { + _onDone(_sink); + } catch (e, s) { + _signalError(new AsyncError(e, s)); + } + } + + /** Default data handler forwards all data. */ + static void _defaultHandleData(dynamic data, StreamSink sink) { + sink.add(data); + } + /** Default error handler forwards all errors. */ + static void _defaultHandleError(AsyncError error, StreamSink sink) { + sink.signalError(error); + } + /** Default done handler forwards done. */ + static void _defaultHandleDone(StreamSink sink) { + sink.close(); + } +} + +/** Creates a [StreamSink] from a [_StreamImpl]'s input methods. */ +class _StreamImplSink implements StreamSink { + _StreamImpl _target; + _StreamImplSink(this._target); + void add(T data) { _target._add(data); } + void signalError(AsyncError error) { _target._signalError(error); } + void close() { _target._close(); } +} + +/** + * A stream pipe that intercepts all events and can generate any event as + * output. + * + * Each incoming event on this [StreamSink] is passed to the corresponding + * method on [transform], along with a [StreamSink] linked to the [output] of + * this pipe. + * The handler can then decide which events to send to the output + */ +class TransformStream extends _ForwardingStream { + final StreamTransformer _transform; + StreamSink _sink; + + TransformStream(StreamTransformer transform) + : this._transform = transform { + // Cache the sink wrapper to avoid creating a new one for each event. + this._sink = new _StreamImplSink(this); + } + + void _handleData(S data) { + try { + return _transform.handleData(data, _sink); + } catch (e, s) { + _controller.signalError(new AsyncError(e, s)); + } + } + + void _handleError(AsyncError error) { + try { + _transform.handleError(error, _sink); + } catch (e, s) { + _controller.signalError(new AsyncError.withCause(e, s, error)); + } + } + + void _handleDone() { + try { + _transform.handleDone(_sink); + } catch (e, s) { + _controller.signalError(new AsyncError(e, s)); + } + } +} + + +/** Helper class for transforming three functions into a StreamTransformer. */ +class _StreamTransformerFunctionWrapper + extends _StreamTransformer { + final _TransformDataHandler _handleData; + final _TransformErrorHandler _handleError; + final _TransformDoneHandler _handleDone; + + _StreamTransformerFunctionWrapper({ + void onData(S data, StreamSink sink), + void onError(AsyncError data, StreamSink sink), + void onDone(StreamSink sink)}) + : _handleData = onData != null ? onData : PipeStream._defaultHandleData, + _handleError = onError != null ? onError + : PipeStream._defaultHandleError, + _handleDone = onDone != null ? onDone : PipeStream._defaultHandleDone; + + void handleData(S data, StreamSink sink) { + return _handleData(data, sink); + } + + void handleError(AsyncError error, StreamSink sink) { + _handleError(error, sink); + } + + void handleDone(StreamSink sink) { + _handleDone(sink); + } +} + + +class TakeStream extends _ForwardingStream { + int _remaining; + + TakeStream(int count) + : this._remaining = count { + if (count is! int) throw new ArgumentError(count); + } + + void _handleData(T inputEvent) { + if (_remaining > 0) { + _add(inputEvent); + _remaining -= 1; + if (_remaining == 0) { + // Closing also unsubscribes all subscribers, which unsubscribes + // this from source. + _close(); + } + } + } +} + + +class TakeWhileStream extends _ForwardingStream { + final _Predicate _test; + + TakeWhileStream(bool test(T value)) + : this._test = test; + + void _handleData(T inputEvent) { + bool satisfies; + try { + satisfies = _test(inputEvent); + } catch (e, s) { + _signalError(new AsyncError(e, s)); + // The test didn't say true. Didn't say false either, but we stop anyway. + _close(); + return; + } + if (satisfies) { + _add(inputEvent); + } else { + _close(); + } + } +} + +class SkipStream extends _ForwardingStream { + int _remaining; + + SkipStream(int count) + : this._remaining = count{ + if (count is! int) throw new ArgumentError(count); + } + + void _handleData(T inputEvent) { + if (_remaining > 0) { + _remaining--; + return; + } + return _add(inputEvent); + } +} + +class SkipWhileStream extends _ForwardingStream { + final _Predicate _test; + bool _hasFailed = false; + + SkipWhileStream(bool test(T value)) + : this._test = test; + + void _handleData(T inputEvent) { + if (_hasFailed) { + _add(inputEvent); + } + bool satisfies; + try { + satisfies = _test(inputEvent); + } catch (e, s) { + _signalError(new AsyncError(e, s)); + // A failure to return a boolean is considered "not matching". + _hasFailed = true; + return; + } + if (!satisfies) { + _hasFailed = true; + _add(inputEvent); + } + } +} + +typedef bool _Equality(T a, T b); + +class DistinctStream extends _ForwardingStream { + static var _SENTINEL = new Object(); + + _Equality _equals; + var _previous = _SENTINEL; + + DistinctStream(bool equals(T a, T b)) + : _equals = equals; + + void _handleData(T inputEvent) { + if (identical(_previous, _SENTINEL)) { + _previous = inputEvent; + return _add(inputEvent); + } else { + bool isEqual; + try { + if (_equals == null) { + isEqual = (_previous == inputEvent); + } else { + isEqual = _equals(_previous, inputEvent); + } + } catch (e, s) { + _signalError(new AsyncError(e, s)); + return null; + } + if (!isEqual) { + _add(inputEvent); + _previous = inputEvent; + } + } + } +} diff --git a/sdk/lib/async/string_transform.dart b/sdk/lib/async/string_transform.dart new file mode 100644 index 00000000000..bd8f4cb3f49 --- /dev/null +++ b/sdk/lib/async/string_transform.dart @@ -0,0 +1,127 @@ +// Copyright (c) 2012, 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. + +// part of dart.async; + +abstract class _StringDecoder extends _StreamTransformer, String> { + + handleData(List bytes, StreamSink sink) { + var data = _carry; + data.addAll(bytes); + _carry = []; + var buffer = new StringBuffer(); + int pos = 0; + while (pos < data.length) { + int currentPos = pos; + int getNext() { + if (pos < data.length) { + return data[pos++]; + } + return -1; + } + _chars = []; + if (_processByte(data[pos++], getNext)) { + _chars.forEach(buffer.addCharCode); + } else { + _carry = data.getRange(currentPos, data.length - currentPos); + break; + } + } + sink.add(buffer.toString()); + } + + void handleDone(StreamSink sink) { + if (!_carry.isEmpty) { + sink.signalError(new AsyncError( + new StateError("Unhandled tailing utf8 chars"))); + } + sink.close(); + } + + bool _processByte(int byte, int getNext()); + + void addChar(int char) { + _chars.add(char); + } + + List _carry = []; + List _chars; +} + +/** + * StringTransformer class that decodes a utf8 encoded bytes. + */ +class Utf8DecoderTransformer extends _StringDecoder { + bool _processByte(int byte, int getNext()) { + int value = byte & 0xFF; + if ((value & 0x80) == 0x80) { + int additionalBytes; + if ((value & 0xe0) == 0xc0) { // 110xxxxx + value = value & 0x1F; + additionalBytes = 1; + } else if ((value & 0xf0) == 0xe0) { // 1110xxxx + value = value & 0x0F; + additionalBytes = 2; + } else { // 11110xxx + value = value & 0x07; + additionalBytes = 3; + } + for (int i = 0; i < additionalBytes; i++) { + int next = getNext(); + if (next < 0) return false; + value = value << 6 | (next & 0x3F); + } + } + addChar(value); + return true; + } +} + + +abstract class _StringEncoder extends _StreamTransformer> { + handleData(String string, StreamSink> sink) { + sink.add(_processString(string)); + } + + List _processString(String string); +} + +/** + * StringTransformer class that utf8 encodes a string. + */ +class Utf8EncoderTransformer extends _StringEncoder { + List _processString(String string) { + var bytes = []; + int pos = 0; + int length = string.length; + for (int i = 0; i < length; i++) { + int additionalBytes; + int charCode = string.charCodeAt(i); + if (charCode <= 0x007F) { + additionalBytes = 0; + bytes.add(charCode); + } else if (charCode <= 0x07FF) { + // 110xxxxx (xxxxx is top 5 bits). + bytes.add(((charCode >> 6) & 0x1F) | 0xC0); + additionalBytes = 1; + } else if (charCode <= 0xFFFF) { + // 1110xxxx (xxxx is top 4 bits) + bytes.add(((charCode >> 12) & 0x0F)| 0xE0); + additionalBytes = 2; + } else { + // 11110xxx (xxx is top 3 bits) + bytes.add(((charCode >> 18) & 0x07) | 0xF0); + additionalBytes = 3; + } + for (int i = additionalBytes; i > 0; i--) { + // 10xxxxxx (xxxxxx is next 6 bits from the top). + bytes.add(((charCode >> (6 * (i - 1))) & 0x3F) | 0x80); + } + pos += additionalBytes + 1; + } + return bytes; + } +} + + diff --git a/sdk/lib/isolate/timer.dart b/sdk/lib/async/timer.dart similarity index 96% rename from sdk/lib/isolate/timer.dart rename to sdk/lib/async/timer.dart index 40d4cd91ec0..6ac023bfa44 100644 --- a/sdk/lib/isolate/timer.dart +++ b/sdk/lib/async/timer.dart @@ -2,7 +2,7 @@ // 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. -part of dart.isolate; +// part of dart.async; abstract class Timer { /** diff --git a/sdk/lib/collection/collections.dart b/sdk/lib/collection/collections.dart index 9224cd1cc06..4bd1fadb513 100644 --- a/sdk/lib/collection/collections.dart +++ b/sdk/lib/collection/collections.dart @@ -23,7 +23,7 @@ class Collections { } } - static bool some(Iterable iterable, bool f(o)) { + static bool any(Iterable iterable, bool f(o)) { for (final e in iterable) { if (f(e)) return true; } @@ -37,13 +37,6 @@ class Collections { return true; } - static List map(Iterable source, List destination, f(o)) { - for (final e in source) { - destination.add(f(e)); - } - return destination; - } - static dynamic reduce(Iterable iterable, dynamic initialValue, dynamic combine(dynamic previousValue, element)) { @@ -53,15 +46,162 @@ class Collections { return initialValue; } - static List filter(Iterable source, List destination, bool f(o)) { - for (final e in source) { - if (f(e)) destination.add(e); - } - return destination; + static bool isEmpty(Iterable iterable) { + return !iterable.iterator.moveNext(); } - static bool isEmpty(Iterable iterable) { - return !iterable.iterator().hasNext; + static dynamic first(Iterable iterable) { + Iterator it = iterable.iterator; + if (!it.moveNext()) { + throw new StateError("No elements"); + } + return it.current; + } + + static dynamic last(Iterable iterable) { + Iterator it = iterable.iterator; + if (!it.moveNext()) { + throw new StateError("No elements"); + } + dynamic result; + do { + result = it.current; + } while(it.moveNext()); + return result; + } + + static dynamic min(Iterable iterable, [int compare(var a, var b)]) { + if (compare == null) compare = Comparable.compare; + Iterator it = iterable.iterator; + if (!it.moveNext()) { + return null; + } + var min = it.current; + while (it.moveNext()) { + if (compare(min, it.current) > 0) min = it.current; + } + return min; + } + + static dynamic max(Iterable iterable, [int compare(var a, var b)]) { + if (compare == null) compare = Comparable.compare; + Iterator it = iterable.iterator; + if (!it.moveNext()) { + return null; + } + var max = it.current; + while (it.moveNext()) { + if (compare(max, it.current) < 0) max = it.current; + } + return max; + } + + static dynamic single(Iterable iterable) { + Iterator it = iterable.iterator; + if (!it.moveNext()) throw new StateError("No elements"); + dynamic result = it.current; + if (it.moveNext()) throw new StateError("More than one element"); + return result; + } + + static dynamic firstMatching(Iterable iterable, + bool test(dynamic value), + dynamic orElse()) { + for (dynamic element in iterable) { + if (test(element)) return element; + } + if (orElse != null) return orElse(); + throw new StateError("No matching element"); + } + + static dynamic lastMatching(Iterable iterable, + bool test(dynamic value), + dynamic orElse()) { + dynamic result = null; + bool foundMatching = false; + for (dynamic element in iterable) { + if (test(element)) { + result = element; + foundMatching = true; + } + } + if (foundMatching) return result; + if (orElse != null) return orElse(); + throw new StateError("No matching element"); + } + + static dynamic lastMatchingInList(List list, + bool test(dynamic value), + dynamic orElse()) { + // TODO(floitsch): check that arguments are of correct type? + for (int i = list.length - 1; i >= 0; i--) { + dynamic element = list[i]; + if (test(element)) return element; + } + if (orElse != null) return orElse(); + throw new StateError("No matching element"); + } + + static dynamic singleMatching(Iterable iterable, bool test(dynamic value)) { + dynamic result = null; + bool foundMatching = false; + for (dynamic element in iterable) { + if (test(element)) { + if (foundMatching) { + throw new StateError("More than one matching element"); + } + result = element; + foundMatching = true; + } + } + if (foundMatching) return result; + throw new StateError("No matching element"); + } + + static dynamic elementAt(Iterable iterable, int index) { + if (index is! int || index < 0) throw new RangeError.value(index); + int remaining = index; + for (dynamic element in iterable) { + if (remaining == 0) return element; + remaining--; + } + throw new RangeError.value(index); + } + + static String join(Iterable iterable, [String separator]) { + Iterator iterator = iterable.iterator; + if (!iterator.moveNext()) return ""; + StringBuffer buffer = new StringBuffer(); + if (separator == null || separator == "") { + do { + buffer.add("${iterator.current}"); + } while (iterator.moveNext()); + } else { + buffer.add("${iterator.current}"); + while (iterator.moveNext()) { + buffer.add(separator); + buffer.add("${iterator.current}"); + } + } + return buffer.toString(); + } + + static String joinList(List list, [String separator]) { + if (list.isEmpty) return ""; + if (list.length == 1) return "${list[0]}"; + StringBuffer buffer = new StringBuffer(); + if (separator == null || separator == "") { + for (int i = 0; i < list.length; i++) { + buffer.add("${list[i]}"); + } + } else { + buffer.add("${list[0]}"); + for (int i = 1; i < list.length; i++) { + buffer.add(separator); + buffer.add("${list[i]}"); + } + } + return buffer.toString(); } // TODO(jjb): visiting list should be an identityHashSet when it exists diff --git a/sdk/lib/core/collection.dart b/sdk/lib/core/collection.dart index 703af889164..23b08e6b4b0 100644 --- a/sdk/lib/core/collection.dart +++ b/sdk/lib/core/collection.dart @@ -11,91 +11,5 @@ part of dart.core; * an iterator based collection. */ abstract class Collection extends Iterable { - /** - * Returns a new collection with the elements [: f(e) :] - * for each element [:e:] of this collection. - * - * Subclasses of [Collection] should implement the [map] method - * to return a collection of the same general type as themselves. - * E.g., [List.map] should return a [List]. - */ - Collection map(f(E element)); - - /** - * Returns a collection with the elements of this collection - * that satisfy the predicate [f]. - * - * The returned collection should be of the same type as the collection - * creating it. - * - * An element satisfies the predicate [f] if [:f(element):] - * returns true. - */ - Collection filter(bool f(E element)); - - /** - * Returns the number of elements in this collection. - */ - int get length; - - /** - * Check whether the collection contains an element equal to [element]. - */ - bool contains(E element) { - for (E e in this) { - if (e == element) return true; - } - return false; - } - - /** - * Applies the function [f] to each element of this collection. - */ - void forEach(void f(E element)) { - for (E element in this) f(element); - } - - /** - * Reduce a collection to a single value by iteratively combining each element - * of the collection with an existing value using the provided function. - * Use [initialValue] as the initial value, and the function [combine] to - * create a new value from the previous one and an element. - * - * Example of calculating the sum of a collection: - * - * collection.reduce(0, (prev, element) => prev + element); - */ - dynamic reduce(var initialValue, - dynamic combine(var previousValue, E element)) { - var value = initialValue; - for (E element in this) value = combine(value, element); - return value; - } - - /** - * Returns true if every elements of this collection satisify the - * predicate [f]. Returns false otherwise. - */ - bool every(bool f(E element)) { - for (E element in this) { - if (!f(element)) return false; - } - return true; - } - - /** - * Returns true if one element of this collection satisfies the - * predicate [f]. Returns false otherwise. - */ - bool some(bool f(E element)) { - for (E element in this) { - if (f(element)) return true; - } - return false; - } - - /** - * Returns true if there is no element in this collection. - */ - bool get isEmpty => !iterator().hasNext; + const Collection(); } diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart index d178451e88f..6dfc93884b4 100644 --- a/sdk/lib/core/core.dart +++ b/sdk/lib/core/core.dart @@ -17,8 +17,6 @@ part "exceptions.dart"; part "expando.dart"; part "expect.dart"; part "function.dart"; -part "future.dart"; -part "future_impl.dart"; part "hashable.dart"; part "identical.dart"; part "int.dart"; @@ -34,8 +32,8 @@ part "pattern.dart"; part "print.dart"; part "queue.dart"; part "regexp.dart"; -part "sequences.dart"; part "set.dart"; +part "sink.dart"; part "sort.dart"; part "stopwatch.dart"; part "string.dart"; diff --git a/sdk/lib/core/corelib_sources.gypi b/sdk/lib/core/corelib_sources.gypi index 91f7ff5c768..b0713c70523 100644 --- a/sdk/lib/core/corelib_sources.gypi +++ b/sdk/lib/core/corelib_sources.gypi @@ -14,8 +14,6 @@ 'errors.dart', 'expando.dart', 'expect.dart', - 'future.dart', - 'future_impl.dart', 'function.dart', 'identical.dart', 'int.dart', @@ -32,9 +30,9 @@ 'print.dart', 'queue.dart', 'regexp.dart', - 'sequences.dart', 'set.dart', 'sort.dart', + 'sink.dart', 'stopwatch.dart', 'string.dart', 'strings.dart', diff --git a/sdk/lib/core/double.dart b/sdk/lib/core/double.dart index a2a63e56207..0b3417f3232 100644 --- a/sdk/lib/core/double.dart +++ b/sdk/lib/core/double.dart @@ -45,9 +45,9 @@ abstract class double extends num { * Truncating division operator. * * The result of the truncating division [:a ~/ b:] is equivalent to - * [:(a / b).truncate():]. + * [:(a / b).truncate().toInt():]. */ - double operator ~/(num other); + int operator ~/(num other); /** Negate operator. */ double operator -(); @@ -99,7 +99,11 @@ abstract class double extends num { * Also recognizes "NaN", "Infinity" and "-Infinity" as inputs and * returns the corresponding double value. * - * Throws a [FormatException] if [source] is not a valid double literal. + * If the [soure] is not a valid double literal, the [handleError] + * is called with the [source] as argument, and its return value is + * used instead. If no handleError is provided, a [FormatException] + * is thrown. */ - external static double parse(String source); + external static double parse(String source, + [double handleError(String source)]); } diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart index 5fbd2d99df8..59f30d03919 100644 --- a/sdk/lib/core/errors.dart +++ b/sdk/lib/core/errors.dart @@ -196,8 +196,8 @@ class NoSuchMethodError implements Error { /** * The operation was not allowed by the object. * - * This [Error] is thrown when a class cannot implement - * one of the methods in its signature. + * This [Error] is thrown when an instance cannot implement one of the methods + * in its signature. */ class UnsupportedError implements Error { final String message; diff --git a/sdk/lib/core/expect.dart b/sdk/lib/core/expect.dart index 6953d06cac8..68b765f0f31 100644 --- a/sdk/lib/core/expect.dart +++ b/sdk/lib/core/expect.dart @@ -120,7 +120,8 @@ class Expect { if (expected.length != actual.length) { _fail('Expect.listEquals(list length, ' 'expected: <${expected.length}>, actual: <${actual.length}>$msg) ' - 'fails'); + 'fails: Next element <' + '${expected.length > n ? expected[n] : actual[n]}>'); } } diff --git a/sdk/lib/core/future.dart b/sdk/lib/core/future.dart deleted file mode 100644 index 93bc6c842e9..00000000000 --- a/sdk/lib/core/future.dart +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) 2012, 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. - -part of dart.core; - -/** - * A [Future] is used to obtain a value sometime in the future. Receivers of a - * [Future] can obtain the value by passing a callback to [then]. For example: - * - * Future future = getFutureFromSomewhere(); - * future.then((value) { - * print("I received the number $value"); - * }); - * - * A future may complete by *succeeding* (producing a value) or *failing* - * (producing an exception, which may be handled with [handleException]). - * Callbacks passed to [onComplete] will be invoked in either case. - * - * When a future completes, the following actions happen in order: - * - * 1. if the future suceeded, handlers registered with [then] are called. - * 2. if the future failed, handlers registered with [handleException] are - * called in sequence, until one returns true. - * 3. handlers registered with [onComplete] are called - * 4. if the future failed, and at least one handler was registered with - * [then], and no handler registered with [handleException] returned - * [:true:], then the exception is thrown. - * - * Use a [Completer] to create and change the state of a [Future]. - */ -abstract class Future { - /** A future whose value is immediately available. */ - factory Future.immediate(T value) => new _FutureImpl.immediate(value); - - /** The value provided. Throws an exception if [hasValue] is false. */ - T get value; - - /** - * Exception that occurred ([:null:] if no exception occured). This property - * throws a [FutureNotCompleteException] if it is used before this future is - * completes. - */ - Object get exception; - - /** - * The stack trace object associated with the exception that occurred. This - * throws a [FutureNotCompleteException] if it is used before the future - * completes. Returns [:null:] if the future completed successfully or a - * stack trace wasn't provided with the exception when it occurred. - */ - Object get stackTrace; - - /** - * Whether the future is complete (either the value is available or there was - * an exception). - */ - bool get isComplete; - - /** - * Whether the value is available (meaning [isComplete] is true, and there was - * no exception). - */ - bool get hasValue; - - /** - * When this future is complete (either with a value or with an exception), - * then [complete] is called with the future. - * If [complete] throws an exception, it is ignored. - */ - void onComplete(void complete(Future future)); - - /** - * If this future is complete and has a value, then [onSuccess] is called - * with the value. - */ - void then(void onSuccess(T value)); - - /** - * If this future is complete and has an exception, then call [onException]. - * - * If [onException] returns true, then the exception is considered handled. - * - * If [onException] does not return true (or [handleException] was never - * called), then the exception is not considered handled. In that case, if - * there were any calls to [then], then the exception will be thrown when the - * value is set. - * - * In most cases it should not be necessary to call [handleException], - * because the exception associated with this [Future] will propagate - * naturally if the future's value is being consumed. Only call - * [handleException] if you need to do some special local exception handling - * related to this particular Future's value. - */ - void handleException(bool onException(Object exception)); - - /** - * A future representing [transformation] applied to this future's value. - * - * When this future gets a value, [transformation] will be called on the - * value, and the returned future will receive the result. - * - * If an exception occurs (received by this future, or thrown by - * [transformation]) then the returned future will receive the exception. - * - * You must not add exception handlers to [this] future prior to calling - * transform, and any you add afterwards will not be invoked. - */ - Future transform(transformation(T value)); - - /** - * A future representing an asynchronous transformation applied to this - * future's value. [transformation] must return a Future. - * - * When this future gets a value, [transformation] will be called on the - * value. When the resulting future gets a value, the returned future - * will receive it. - * - * If an exception occurs (received by this future, thrown by - * [transformation], or received by the future returned by [transformation]) - * then the returned future will receive the exception. - * - * You must not add exception handlers to [this] future prior to calling - * chain, and any you add afterwards will not be invoked. - */ - Future chain(Future transformation(T value)); - - /** - * A future representing [transformation] applied to this future's exception. - * This can be used to "catch" an exception coming from `this` and translate - * it to a more appropriate result. - * - * If this future gets a value, it simply completes to that same value. If an - * exception occurs, then [transformation] will be called with the exception - * value. If [transformation] itself throws an exception, then the returned - * future completes with that exception. Otherwise, the future will complete - * with the value returned by [transformation]. If the returned value is - * itself a future, then the future returned by [transformException] will - * complete with the value that that future completes to. - */ - Future transformException(transformation(Object exception)); -} - -/** - * A [Completer] is used to produce [Future]s and supply their value when it - * becomes available. - * - * A service that provides values to callers, and wants to return [Future]s can - * use a [Completer] as follows: - * - * Completer completer = new Completer(); - * // send future object back to client... - * return completer.future; - * ... - * - * // later when value is available, call: - * completer.complete(value); - * - * // alternatively, if the service cannot produce the value, it - * // can provide an exception: - * completer.completeException(exception); - * - */ -abstract class Completer { - - factory Completer() => new _CompleterImpl(); - - /** The future that will contain the value produced by this completer. */ - Future get future; - - /** Supply a value for [future]. */ - void complete(T value); - - /** - * Indicate in [future] that an exception occured while trying to produce its - * value. The argument [exception] should not be [:null:]. A [stackTrace] - * object can be provided as well to give the user information about where - * the error occurred. If omitted, it will be [:null:]. - */ - void completeException(Object exception, [Object stackTrace]); -} - -/** Thrown when reading a future's properties before it is complete. */ -class FutureNotCompleteException implements Exception { - FutureNotCompleteException() {} - String toString() => "Exception: future has not been completed"; -} - -/** - * Thrown if a completer tries to set the value on a future that is already - * complete. - */ -class FutureAlreadyCompleteException implements Exception { - FutureAlreadyCompleteException() {} - String toString() => "Exception: future already completed"; -} - -/** - * Wraps unhandled exceptions provided to [Completer.completeException]. It is - * used to show both the error message and the stack trace for unhandled - * exceptions. - */ -class FutureUnhandledException implements Exception { - /** Wrapped exception. */ - var source; - - /** Trace for the wrapped exception. */ - Object stackTrace; - - FutureUnhandledException(this.source, this.stackTrace); - - String toString() { - return 'FutureUnhandledException: exception while executing Future\n ' - '${source.toString().replaceAll("\n", "\n ")}\n' - 'original stack trace:\n ' - '${stackTrace.toString().replaceAll("\n","\n ")}'; - } -} - - -/** - * [Futures] holds additional utility functions that operate on [Future]s (for - * example, waiting for a collection of Futures to complete). - */ -class Futures { - /** - * Returns a future which will complete once all the futures in a list are - * complete. If any of the futures in the list completes with an exception, - * the resulting future also completes with an exception. (The value of the - * returned future will be a list of all the values that were produced.) - */ - static Future wait(List futures) { - if (futures.isEmpty) { - return new Future.immediate(const []); - } - - Completer completer = new Completer(); - Future result = completer.future; - int remaining = futures.length; - List values = new List(futures.length); - - // As each future completes, put its value into the corresponding - // position in the list of values. - for (int i = 0; i < futures.length; i++) { - // TODO(mattsh) - remove this after bug - // http://code.google.com/p/dart/issues/detail?id=333 is fixed. - int pos = i; - Future future = futures[pos]; - future.then((Object value) { - values[pos] = value; - if (--remaining == 0 && !result.isComplete) { - completer.complete(values); - } - }); - future.handleException((exception) { - if (!result.isComplete) { - completer.completeException(exception, future.stackTrace); - } - return true; - }); - } - return result; - } - - /** - * Runs [f] for each element in [input] in order, moving to the next element - * only when the [Future] returned by [f] completes. Returns a [Future] that - * completes when all elements have been processed. - * - * The return values of all [Future]s are discarded. Any errors will cause the - * iteration to stop and will be piped through the returned [Future]. - */ - static Future forEach(Iterable input, Future f(element)) { - var iterator = input.iterator(); - Future nextElement(_) { - if (!iterator.hasNext) return new Future.immediate(null); - return f(iterator.next()).chain(nextElement); - } - return nextElement(null); - } -} diff --git a/sdk/lib/core/future_impl.dart b/sdk/lib/core/future_impl.dart deleted file mode 100644 index 693d1478131..00000000000 --- a/sdk/lib/core/future_impl.dart +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// Dart core library. - -part of dart.core; - -class _FutureImpl implements Future { - - bool _isComplete = false; - - /** - * Value that was provided to this Future by the Completer - */ - T _value; - - /** - * Exception that occured, if there was a problem providing - * Value. - */ - Object _exception; - - /** - * Stack trace associated with [_exception], if one was provided. - */ - Object _stackTrace; - - /** - * true, if any onException handler handled the exception. - */ - bool _exceptionHandled = false; - - /** - * true if an exception in this future should be thrown to the top level. - */ - bool _throwOnException = false; - - /** - * Listeners waiting to receive the value of this future. - */ - final List _successListeners; - - /** - * Exception handlers waiting for exceptions. - */ - final List _exceptionHandlers; - - /** - * Listeners waiting to be called when the future completes. - */ - final List _completionListeners; - - _FutureImpl() - : _successListeners = [], - _exceptionHandlers = [], - _completionListeners = []; - - factory _FutureImpl.immediate(T value) { - final res = new _FutureImpl(); - res._setValue(value); - return res; - } - - T get value { - if (!isComplete) { - throw new FutureNotCompleteException(); - } - if (_exception != null) { - throw new FutureUnhandledException(_exception, stackTrace); - } - return _value; - } - - Object get exception { - if (!isComplete) { - throw new FutureNotCompleteException(); - } - return _exception; - } - - Object get stackTrace { - if (!isComplete) { - throw new FutureNotCompleteException(); - } - return _stackTrace; - } - - bool get isComplete { - return _isComplete; - } - - bool get hasValue { - return isComplete && _exception == null; - } - - void then(void onSuccess(T value)) { - if (hasValue) { - onSuccess(value); - } else if (!isComplete) { - _throwOnException = true; - _successListeners.add(onSuccess); - } else if (!_exceptionHandled) { - throw new FutureUnhandledException(_exception, stackTrace); - } - } - - void _handleSuccess(void onSuccess(T value)) { - if (hasValue) { - onSuccess(value); - } else if (!isComplete) { - _successListeners.add(onSuccess); - } - } - - void handleException(bool onException(Object exception)) { - if (_exceptionHandled) return; - if (_isComplete) { - if (_exception != null) { - _exceptionHandled = onException(_exception); - } - } else { - _exceptionHandlers.add(onException); - } - } - - void onComplete(void complete(Future future)) { - if (_isComplete) { - try { - complete(this); - } catch (e) {} - } else { - _completionListeners.add(complete); - } - } - - void _complete() { - _isComplete = true; - - try { - if (_exception != null) { - for (Function handler in _exceptionHandlers) { - // Explicitly check for true here so that if the handler returns null, - // we don't get an exception in checked mode. - if (handler(_exception) == true) { - _exceptionHandled = true; - break; - } - } - } - - if (hasValue) { - for (Function listener in _successListeners) { - listener(value); - } - } else { - if (!_exceptionHandled && _throwOnException) { - throw new FutureUnhandledException(_exception, stackTrace); - } - } - } finally { - for (Function listener in _completionListeners) { - try { - listener(this); - } catch (e) {} - } - } - } - - void _setValue(T value) { - if (_isComplete) { - throw new FutureAlreadyCompleteException(); - } - _value = value; - _complete(); - } - - void _setException(Object exception, Object stackTrace) { - if (exception == null) { - // null is not a legal value for the exception of a Future. - throw new ArgumentError(null); - } - if (_isComplete) { - throw new FutureAlreadyCompleteException(); - } - _exception = exception; - _stackTrace = stackTrace; - _complete(); - } - - Future transform(Function transformation) { - final completer = new Completer(); - - _forwardException(this, completer); - - _handleSuccess((v) { - var transformed = null; - try { - transformed = transformation(v); - } catch (e, stackTrace) { - completer.completeException(e, stackTrace); - return; - } - completer.complete(transformed); - }); - - return completer.future; - } - - Future chain(Function transformation) { - final completer = new Completer(); - - _forwardException(this, completer); - _handleSuccess((v) { - var future = null; - try { - future = transformation(v); - } catch (ex, stackTrace) { - completer.completeException(ex, stackTrace); - return; - } - - _forward(future, completer); - }); - return completer.future; - } - - Future transformException(transformation(Object exception)) { - final completer = new Completer(); - - handleException((ex) { - try { - final result = transformation(ex); - - // If the transformation itself returns a future, then we will - // complete to what that completes to. - if (result is Future) { - _forward(result, completer); - } else { - completer.complete(result); - } - } catch (innerException, stackTrace) { - if (identical(ex, innerException)) { - completer.completeException(innerException, this.stackTrace); - } else { - completer.completeException(innerException, stackTrace); - } - } - return false; - }); - - _handleSuccess(completer.complete); - - return completer.future; - } - - /** - * Forwards the success or error completion from [future] to [completer]. - */ - _forward(Future future, Completer completer) { - _forwardException(future, completer); - future._handleSuccess(completer.complete); - } - - /** - * Forwards the exception completion from [future] to [completer]. - */ - _forwardException(Future future, Completer completer) { - future.handleException((e) { - completer.completeException(e, future.stackTrace); - return false; - }); - } -} - -class _CompleterImpl implements Completer { - - final _FutureImpl _futureImpl; - - _CompleterImpl() : _futureImpl = new _FutureImpl() {} - - Future get future { - return _futureImpl; - } - - void complete(T value) { - _futureImpl._setValue(value); - } - - void completeException(Object exception, [Object stackTrace]) { - _futureImpl._setException(exception, stackTrace); - } -} - diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart index 261d2c4965c..2262574c7dd 100644 --- a/sdk/lib/core/int.dart +++ b/sdk/lib/core/int.dart @@ -69,13 +69,38 @@ abstract class int extends num { */ String toString(); + /** + * Converts [this] to a string representation in the given [radix]. + * + * In the string representation, lower-case letters are used for digits above + * '9'. + * + * The [radix] argument must be an integer in the range 2 to 36. + */ + String toRadixString(int radix); + /** * Parse [source] as an integer literal and return its value. * - * Accepts "0x" prefix for hexadecimal numbers, otherwise defaults - * to base-10. + * The [radix] must be in the range 2..36. The digits used are + * first the decimal digits 0..9, and then the letters 'a'..'z'. + * Accepts capital letters as well. * - * Throws a [FormatException] if [source] is not a valid integer literal. + * If no [radix] is given then it defaults to 16 if the string starts + * with "0x", "-0x" or "+0x" and 10 otherwise. + * + * The [source] must be a non-empty sequence of base-[radix] digits, + * optionally prefixed with a minus or plus sign ('-' or '+'). + * + * It must always be the case for an int [:n:] and radix [:r:] that + * [:n == parseRadix(n.toRadixString(r), r):]. + * + * If the [source] is not a valid integer literal, optionally prefixed by a + * sign, the [onError] is called with the [source] as argument, and its return + * value is used instead. If no [onError] is provided, a [FormatException] + * is thrown. */ - external static int parse(String source); + external static int parse(String source, + { int radix, + int onError(String source) }); } diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart index 8e258859fd5..d150ab32746 100644 --- a/sdk/lib/core/iterable.dart +++ b/sdk/lib/core/iterable.dart @@ -17,8 +17,558 @@ part of dart.core; * be used as the right-hand side of a for-in construct. */ abstract class Iterable { + const Iterable(); + /** * Returns an [Iterator] that iterates over this [Iterable] object. */ - Iterator iterator(); + Iterator get iterator; + + /** + * Returns a lazy [Iterable] where each element [:e:] of [this] is replaced + * by the result of [:f(e):]. + * + * This method returns a view of the mapped elements. As long as the + * returned [Iterable] is not iterated over, the supplied function [f] will + * not be invoked. The transformed elements will not be cached. Iterating + * multiple times over the the returned [Iterable] will invoke the supplied + * function [f] multiple times on the same element. + */ + Iterable mappedBy(f(E element)) => new MappedIterable(this, f); + + /** + * Returns a lazy [Iterable] with all elements that satisfy the + * predicate [f]. + * + * This method returns a view of the mapped elements. As long as the + * returned [Iterable] is not iterated over, the supplied function [f] will + * not be invoked. Iterating will not cache results, and thus iterating + * multiple times over the the returned [Iterable] will invoke the supplied + * function [f] multiple times on the same element. + */ + Iterable where(bool f(E element)) => new WhereIterable(this, f); + + /** + * Check whether the collection contains an element equal to [element]. + */ + bool contains(E element) { + for (E e in this) { + if (e == element) return true; + } + return false; + } + + /** + * Applies the function [f] to each element of this collection. + */ + void forEach(void f(E element)) { + for (E element in this) f(element); + } + + /** + * Reduce a collection to a single value by iteratively combining each element + * of the collection with an existing value using the provided function. + * Use [initialValue] as the initial value, and the function [combine] to + * create a new value from the previous one and an element. + * + * Example of calculating the sum of a collection: + * + * collection.reduce(0, (prev, element) => prev + element); + */ + dynamic reduce(var initialValue, + dynamic combine(var previousValue, E element)) { + var value = initialValue; + for (E element in this) value = combine(value, element); + return value; + } + + /** + * Returns true if every elements of this collection satisify the + * predicate [f]. Returns false otherwise. + */ + bool every(bool f(E element)) { + for (E element in this) { + if (!f(element)) return false; + } + return true; + } + + /** + * Convert each element to a [String] and concatenate the strings. + * + * Converts each element to a [String] by calling [Object.toString] on it. + * Then concatenates the strings, optionally separated by the [separator] + * string. + */ + String join([String separator]) { + Iterator iterator = this.iterator; + if (!iterator.moveNext()) return ""; + StringBuffer buffer = new StringBuffer(); + if (separator == null || separator == "") { + do { + buffer.add("${iterator.current}"); + } while (iterator.moveNext()); + } else { + buffer.add("${iterator.current}"); + while (iterator.moveNext()) { + buffer.add(separator); + buffer.add("${iterator.current}"); + } + } + return buffer.toString(); + } + + /** + * Returns true if one element of this collection satisfies the + * predicate [f]. Returns false otherwise. + */ + bool any(bool f(E element)) { + for (E element in this) { + if (f(element)) return true; + } + return false; + } + + List toList() => new List.from(this); + Set toSet() => new Set.from(this); + + /** + * Returns the number of elements in [this]. + * + * Counting all elements may be involve running through all elements and can + * therefore be slow. + */ + int get length { + int count = 0; + Iterator it = iterator; + while (it.moveNext()) { + count++; + } + return count; + } + + /** + * Find the least element in the iterable. + * + * Returns null if the iterable is empty. + * Otherwise returns an element [:x:] of this [Iterable] so that + * [:x:] is not greater than [:y:] (that is, [:compare(x, y) <= 0:]) for all + * other elements [:y:] in the iterable. + * + * The [compare] function must be a proper [Comparator]. If a function is + * not provided, [compare] defaults to [Comparable.compare]. + */ + E min([int compare(E a, E b)]) { + if (compare == null) compare = Comparable.compare; + Iterator it = iterator; + if (!it.moveNext()) return null; + E min = it.current; + while (it.moveNext()) { + E current = it.current; + if (compare(min, current) > 0) min = current; + } + return min; + } + + /** + * Find the largest element in the iterable. + * + * Returns null if the iterable is empty. + * Otherwise returns an element [:x:] of this [Iterable] so that + * [:x:] is not smaller than [:y:] (that is, [:compare(x, y) >= 0:]) for all + * other elements [:y:] in the iterable. + * + * The [compare] function must be a proper [Comparator]. If a function is + * not provided, [compare] defaults to [Comparable.compare]. + */ + E max([int compare(E a, E b)]) { + if (compare == null) compare = Comparable.compare; + Iterator it = iterator; + if (!it.moveNext()) return null; + E max = it.current; + while (it.moveNext()) { + E current = it.current; + if (compare(max, current) < 0) max = current; + } + return max; + } + + /** + * Returns true if there is no element in this collection. + */ + bool get isEmpty => !iterator.moveNext(); + + /** + * Returns an [Iterable] with at most [n] elements. + * + * The returned [Iterable] may contain fewer than [n] elements, if [this] + * contains fewer than [n] elements. + */ + Iterable take(int n) { + return new TakeIterable(this, n); + } + + /** + * Returns an [Iterable] that stops once [test] is not satisfied anymore. + * + * The filtering happens lazily. Every new [Iterator] of the returned + * [Iterable] will start iterating over the elements of [this]. + * When the iterator encounters an element [:e:] that does not satisfy [test], + * it discards [:e:] and moves into the finished state. That is, it will not + * ask or provide any more elements. + */ + Iterable takeWhile(bool test(E value)) { + return new TakeWhileIterable(this, test); + } + + /** + * Returns an [Iterable] that skips the first [n] elements. + * + * If [this] has fewer than [n] elements, then the resulting [Iterable] will + * be empty. + */ + Iterable skip(int n) { + return new SkipIterable(this, n); + } + + /** + * Returns an [Iterable] that skips elements while [test] is satisfied. + * + * The filtering happens lazily. Every new [Iterator] of the returned + * [Iterable] will iterate over all elements of [this]. + * As long as the iterator's elements do not satisfy [test] they are + * discarded. Once an element satisfies the [test] the iterator stops testing + * and uses every element unconditionally. + */ + Iterable skipWhile(bool test(E value)) { + return new SkipWhileIterable(this, test); + } + + /** + * Returns the first element. + * + * If [this] is empty throws a [StateError]. Otherwise this method is + * equivalent to [:this.elementAt(0):] + */ + E get first { + Iterator it = iterator; + if (!it.moveNext()) { + throw new StateError("No elements"); + } + return it.current; + } + + /** + * Returns the last element. + * + * If [this] is empty throws a [StateError]. + */ + E get last { + Iterator it = iterator; + if (!it.moveNext()) { + throw new StateError("No elements"); + } + E result; + do { + result = it.current; + } while(it.moveNext()); + return result; + } + + /** + * Returns the single element in [this]. + * + * If [this] is empty or has more than one element throws a [StateError]. + */ + E get single { + Iterator it = iterator; + if (!it.moveNext()) throw new StateError("No elements"); + E result = it.current; + if (it.moveNext()) throw new StateError("More than one element"); + return result; + } + + /** + * Returns the first element that satisfies the given predicate [f]. + * + * If none matches, the result of invoking the [orElse] function is + * returned. By default, when [orElse] is `null`, a [StateError] is + * thrown. + */ + E firstMatching(bool test(E value), { E orElse() }) { + // TODO(floitsch): check that arguments are of correct type? + for (E element in this) { + if (test(element)) return element; + } + if (orElse != null) return orElse(); + throw new StateError("No matching element"); + } + + /** + * Returns the last element that satisfies the given predicate [f]. + * + * If none matches, the result of invoking the [orElse] function is + * returned. By default, when [orElse] is [:null:], a [StateError] is + * thrown. + */ + E lastMatching(bool test(E value), {E orElse()}) { + // TODO(floitsch): check that arguments are of correct type? + E result = null; + bool foundMatching = false; + for (E element in this) { + if (test(element)) { + result = element; + foundMatching = true; + } + } + if (foundMatching) return result; + if (orElse != null) return orElse(); + throw new StateError("No matching element"); + } + + /** + * Returns the single element that satisfies [f]. If no or more than one + * element match then a [StateError] is thrown. + */ + E singleMatching(bool test(E value)) { + // TODO(floitsch): check that argument is of correct type? + E result = null; + bool foundMatching = false; + for (E element in this) { + if (test(element)) { + if (foundMatching) { + throw new StateError("More than one matching element"); + } + result = element; + foundMatching = true; + } + } + if (foundMatching) return result; + throw new StateError("No matching element"); + } + + /** + * Returns the [index]th element. + * + * If [this] [Iterable] has fewer than [index] elements throws a + * [RangeError]. + * + * Note: if [this] does not have a deterministic iteration order then the + * function may simply return any element without any iteration if there are + * at least [index] elements in [this]. + */ + E elementAt(int index) { + if (index is! int || index < 0) throw new RangeError.value(index); + int remaining = index; + for (E element in this) { + if (remaining == 0) return element; + remaining--; + } + throw new RangeError.value(index); + } +} + +typedef T _Transformation(S value); + +class MappedIterable extends Iterable { + final Iterable _iterable; + final _Transformation _f; + + MappedIterable(this._iterable, T this._f(S element)); + + Iterator get iterator => new MappedIterator(_iterable.iterator, _f); + + // Length related functions are independent of the mapping. + int get length => _iterable.length; + bool get isEmpty => _iterable.isEmpty; +} + +class MappedIterator extends Iterator { + T _current; + final Iterator _iterator; + final _Transformation _f; + + MappedIterator(this._iterator, T this._f(S element)); + + bool moveNext() { + if (_iterator.moveNext()) { + _current = _f(_iterator.current); + return true; + } else { + _current = null; + return false; + } + } + + T get current => _current; +} + +typedef bool _ElementPredicate(E element); + +class WhereIterable extends Iterable { + final Iterable _iterable; + final _ElementPredicate _f; + + WhereIterable(this._iterable, bool this._f(E element)); + + Iterator get iterator => new WhereIterator(_iterable.iterator, _f); +} + +class WhereIterator extends Iterator { + final Iterator _iterator; + final _ElementPredicate _f; + + WhereIterator(this._iterator, bool this._f(E element)); + + bool moveNext() { + while (_iterator.moveNext()) { + if (_f(_iterator.current)) { + return true; + } + } + return false; + } + + E get current => _iterator.current; +} + +class TakeIterable extends Iterable { + final Iterable _iterable; + final int _takeCount; + + TakeIterable(this._iterable, this._takeCount) { + if (_takeCount is! int || _takeCount < 0) { + throw new ArgumentError(_takeCount); + } + } + + Iterator get iterator { + return new TakeIterator(_iterable.iterator, _takeCount); + } +} + +class TakeIterator extends Iterator { + final Iterator _iterator; + int _remaining; + + TakeIterator(this._iterator, this._remaining) { + assert(_remaining is int && _remaining >= 0); + } + + bool moveNext() { + _remaining--; + if (_remaining >= 0) { + return _iterator.moveNext(); + } + _remaining = -1; + return false; + } + + E get current { + if (_remaining < 0) return null; + return _iterator.current; + } +} + +class TakeWhileIterable extends Iterable { + final Iterable _iterable; + final _ElementPredicate _f; + + TakeWhileIterable(this._iterable, bool this._f(E element)); + + Iterator get iterator { + return new TakeWhileIterator(_iterable.iterator, _f); + } +} + +class TakeWhileIterator extends Iterator { + final Iterator _iterator; + final _ElementPredicate _f; + bool _isFinished = false; + + TakeWhileIterator(this._iterator, bool this._f(E element)); + + bool moveNext() { + if (_isFinished) return false; + if (!_iterator.moveNext() || !_f(_iterator.current)) { + _isFinished = true; + return false; + } + return true; + } + + E get current { + if (_isFinished) return null; + return _iterator.current; + } +} + +class SkipIterable extends Iterable { + final Iterable _iterable; + final int _skipCount; + + SkipIterable(this._iterable, this._skipCount) { + if (_skipCount is! int || _skipCount < 0) { + throw new ArgumentError(_skipCount); + } + } + + Iterable skip(int n) { + if (n is! int || n < 0) { + throw new ArgumentError(n); + } + return new SkipIterable(_iterable, _skipCount + n); + } + + Iterator get iterator { + return new SkipIterator(_iterable.iterator, _skipCount); + } +} + +class SkipIterator extends Iterator { + final Iterator _iterator; + int _skipCount; + + SkipIterator(this._iterator, this._skipCount) { + assert(_skipCount is int && _skipCount >= 0); + } + + bool moveNext() { + for (int i = 0; i < _skipCount; i++) _iterator.moveNext(); + _skipCount = 0; + return _iterator.moveNext(); + } + + E get current => _iterator.current; +} + +class SkipWhileIterable extends Iterable { + final Iterable _iterable; + final _ElementPredicate _f; + + SkipWhileIterable(this._iterable, bool this._f(E element)); + + Iterator get iterator { + return new SkipWhileIterator(_iterable.iterator, _f); + } +} + +class SkipWhileIterator extends Iterator { + final Iterator _iterator; + final _ElementPredicate _f; + bool _hasSkipped = false; + + SkipWhileIterator(this._iterator, bool this._f(E element)); + + bool moveNext() { + if (!_hasSkipped) { + _hasSkipped = true; + while (_iterator.moveNext()) { + if (!_f(_iterator.current)) return true; + } + } + return _iterator.moveNext(); + } + + E get current => _iterator.current; } diff --git a/sdk/lib/core/iterator.dart b/sdk/lib/core/iterator.dart index bd4a595f466..12c4a72a976 100644 --- a/sdk/lib/core/iterator.dart +++ b/sdk/lib/core/iterator.dart @@ -11,16 +11,62 @@ part of dart.core; * * If the object iterated over is changed during the iteration, the * behavior is unspecified. + * + * The [Iterator] is initially positioned before the first element. Before + * accessing the first element the iterator must thus be advanced ([moveNext]) + * to point to the first element. If there is no element left, then [moveNext] + * returns false. */ abstract class Iterator { /** - * Gets the next element in the iteration. Throws a - * [StateError] if no element is left. + * Moves to the next element. Returns true if [current] contains the next + * element. Returns false, if no element was left. + * + * It is safe to invoke [moveNext] even when the iterator is already + * positioned after the last element. In this case [moveNext] has no effect. */ - E next(); + bool moveNext(); /** - * Returns whether the [Iterator] has elements left. + * Returns the current element. + * + * Return [:null:] if the iterator has not yet been moved to the first + * element, or if the iterator has been moved after the last element of the + * [Iterable]. */ - bool get hasNext; + E get current; +} + +class HasNextIterator { + static const int _HAS_NEXT_AND_NEXT_IN_CURRENT = 0; + static const int _NO_NEXT = 1; + static const int _NOT_MOVED_YET = 2; + + Iterator _iterator; + int _state = _NOT_MOVED_YET; + + HasNextIterator(this._iterator); + + bool get hasNext { + if (_state == _NOT_MOVED_YET) _move(); + return _state == _HAS_NEXT_AND_NEXT_IN_CURRENT; + } + + E next() { + // Call to hasNext is necessary to make sure we are positioned at the first + // element when we start iterating. + if (!hasNext) throw new StateError("No more elements"); + assert(_state == _HAS_NEXT_AND_NEXT_IN_CURRENT); + E result = _iterator.current; + _move(); + return result; + } + + void _move() { + if (_iterator.moveNext()) { + _state = _HAS_NEXT_AND_NEXT_IN_CURRENT; + } else { + _state = _NO_NEXT; + } + } } diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart index e5230992f37..e86e5aa96c9 100644 --- a/sdk/lib/core/list.dart +++ b/sdk/lib/core/list.dart @@ -8,21 +8,33 @@ part of dart.core; * A [List] is an indexable collection with a length. It can be of * fixed size or extendable. */ -abstract class List implements Collection, Sequence { +abstract class List implements Collection { /** * Creates a list of the given [length]. * - * If no [length] argument is supplied an extendable list of - * length 0 is created. - * - * If a [length] argument is supplied, a fixed size list of that - * length is created. + * The length of the returned list is not fixed. */ - external factory List([int length]); + external factory List([int length = 0]); /** - * Creates a list with the elements of [other]. The order in + * Creates a fixed-sized list of the given [length] where each entry is + * filled with [fill]. + */ + external factory List.fixedLength(int length, {E fill: null}); + + /** + * Creates an list of the given [length] where each entry is + * filled with [fill]. + * + * The length of the returned list is not fixed. + */ + external factory List.filled(int length, E fill); + + /** + * Creates an list with the elements of [other]. The order in * the list will be the order provided by the iterator of [other]. + * + * The length of the returned list is not fixed. */ factory List.from(Iterable other) { var list = new List(); @@ -66,12 +78,11 @@ abstract class List implements Collection, Sequence { void addLast(E value); /** - * Appends all elements of the [collection] to the end of this list. - * Extends the length of the list by the number of elements in [collection]. - * Throws an [UnsupportedError] if this list is not - * extendable. + * Appends all elements of the [iterable] to the end of this list. + * Extends the length of the list by the number of elements in [iterable]. + * Throws an [UnsupportedError] if this list is not extensible. */ - void addAll(Collection collection); + void addAll(Iterable iterable); /** * Sorts the list according to the order specified by the [compare] function. @@ -133,18 +144,6 @@ abstract class List implements Collection, Sequence { */ E removeLast(); - /** - * Returns the first element of the list, or throws an out of bounds - * exception if the list is empty. - */ - E get first; - - /** - * Returns the last element of the list, or throws an out of bounds - * exception if the list is empty. - */ - E get last; - /** * Returns a new list containing [length] elements from the list, * starting at [start]. @@ -179,7 +178,7 @@ abstract class List implements Collection, Sequence { /** * Inserts a new range into the list, starting from [start] to - * [:start + length - 1:]. The entries are filled with [initialValue]. + * [:start + length - 1:]. The entries are filled with [fill]. * Throws an [UnsupportedError] if the list is * not extendable. * If [length] is 0, this method does not do anything. @@ -189,5 +188,246 @@ abstract class List implements Collection, Sequence { * Throws an [RangeError] if [start] is negative or if * [start] is greater than the length of the list. */ - void insertRange(int start, int length, [E initialValue]); + void insertRange(int start, int length, [E fill]); +} + +/** + * An unmodifiable [List]. + */ +abstract class NonExtensibleListMixin + extends Iterable implements List { + + Iterator get iterator => new ListIterator(this); + + void forEach(f(E element)) { + for (int i = 0; i < this.length; i++) f(this[i]); + } + + bool contains(E value) { + for (int i = 0; i < length; i++) { + if (this[i] == value) return true; + } + return false; + } + + reduce(initialValue, combine(previousValue, E element)) { + var value = initialValue; + for (int i = 0; i < this.length; i++) { + value = combine(value, this[i]); + } + return value; + } + + bool every(bool f(E element)) { + for (int i = 0; i < this.length; i++) { + if (!f(this[i])) return false; + } + return true; + } + + bool any(bool f(E element)) { + for (int i = 0; i < this.length; i++) { + if (f(this[i])) return true; + } + return false; + } + + bool get isEmpty { + return this.length == 0; + } + + E elementAt(int index) { + return this[index]; + } + + int indexOf(E value, [int start = 0]) { + for (int i = start; i < length; i++) { + if (this[i] == value) return i; + } + return -1; + } + + int lastIndexOf(E value, [int start]) { + if (start == null) start = length - 1; + for (int i = start; i >= 0; i--) { + if (this[i] == value) return i; + } + return -1; + } + + E get first { + if (length > 0) return this[0]; + throw new StateError("No elements"); + } + + E get last { + if (length > 0) return this[length - 1]; + throw new StateError("No elements"); + } + + E get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + List getRange(int start, int length) { + List result = []; + for (int i = 0; i < length; i++) { + result.add(this[start + i]); + } + return result; + } + + void operator []=(int index, E value) { + throw new UnsupportedError( + "Cannot modify an unmodifiable list"); + } + + void set length(int newLength) { + throw new UnsupportedError( + "Cannot change the length of an unmodifiable list"); + } + + void add(E value) { + throw new UnsupportedError( + "Cannot add to an unmodifiable list"); + } + + void addLast(E value) { + throw new UnsupportedError( + "Cannot add to an unmodifiable list"); + } + + void addAll(Iterable iterable) { + throw new UnsupportedError( + "Cannot add to an unmodifiable list"); + } + + void sort([Comparator compare]) { + throw new UnsupportedError( + "Cannot modify an unmodifiable list"); + } + + void clear() { + throw new UnsupportedError( + "Cannot clear an unmodifiable list"); + } + + E removeAt(int index) { + throw new UnsupportedError( + "Cannot remove in an unmodifiable list"); + } + + E removeLast() { + throw new UnsupportedError( + "Cannot remove in an unmodifiable list"); + } + + void setRange(int start, int length, List from, [int startFrom]) { + throw new UnsupportedError( + "Cannot modify an unmodifiable list"); + } + + void removeRange(int start, int length) { + throw new UnsupportedError( + "Cannot remove in an unmodifiable list"); + } + + void insertRange(int start, int length, [E initialValue]) { + throw new UnsupportedError( + "Cannot insert range in an unmodifiable list"); + } +} + +/** + * Iterates over a [Sequence] in growing index order. + */ +class ListIterator implements Iterator { + final List _list; + int _position; + E _current; + + ListIterator(this._list) : _position = -1; + + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _list.length) { + _current = _list[nextPosition]; + _position = nextPosition; + return true; + } + _position = _list.length; + _current = null; + return false; + } + + E get current => _current; +} + +class MappedList extends NonExtensibleListMixin { + final List _list; + final _Transformation _f; + + MappedList(this._list, T this._f(S element)); + + T operator[](int index) => _f(_list[index]); + int get length => _list.length; +} + +/** + * An immutable view of a [List]. + */ +class ListView extends NonExtensibleListMixin { + final List _list; + final int _offset; + final int _length; + + /** + * If the given length is `null` then the ListView's length is bound by + * the backed [list]. + */ + ListView(List list, this._offset, this._length) : _list = list { + if (_offset is! int || _offset < 0) { + throw new ArgumentError(_offset); + } + if (_length != null && + (_length is! int || _length < 0)) { + throw new ArgumentError(_length); + } + } + + int get length { + int originalLength = _list.length; + int skipLength = originalLength - _offset; + if (skipLength < 0) return 0; + if (_length == null || _length > skipLength) return skipLength; + return _length; + } + + E operator[](int index) { + int skipIndex = index + _offset; + if (index < 0 || + (_length != null && index >= _length) || + index + _offset >= _list.length) { + throw new RangeError.value(index); + } + return _list[index + _offset]; + } + + ListView skip(int skipCount) { + if (skipCount is! int || skipCount < 0) { + throw new ArgumentError(skipCount); + } + return new ListView(_list, _offset + skipCount, _length); + } + + ListView take(int takeCount) { + if (takeCount is! int || takeCount < 0) { + throw new ArgumentError(takeCount); + } + int newLength = takeCount; + if (_length != null && takeCount > _length) newLength = _length; + return new ListView(_list, _offset, newLength); + } } diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart index 9a651f992b4..9b2b66675e0 100644 --- a/sdk/lib/core/map.dart +++ b/sdk/lib/core/map.dart @@ -69,14 +69,15 @@ abstract class Map { void forEach(void f(K key, V value)); /** - * Returns a collection containing all the keys in the map. + * The keys of [this]. */ - Collection get keys; + // TODO(floitsch): this should return a [Set]. + Iterable get keys; /** - * Returns a collection containing all the values in the map. + * The values of [this]. */ - Collection get values; + Iterable get values; /** * The number of {key, value} pairs in the map. @@ -168,8 +169,8 @@ class _HashMapImpl implements HashMap { _numberOfEntries = 0; _numberOfDeleted = 0; _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); - _keys = new List(_INITIAL_CAPACITY); - _values = new List(_INITIAL_CAPACITY); + _keys = new List.fixedLength(_INITIAL_CAPACITY); + _values = new List.fixedLength(_INITIAL_CAPACITY); } factory _HashMapImpl.from(Map other) { @@ -275,8 +276,8 @@ class _HashMapImpl implements HashMap { _loadLimit = _computeLoadLimit(newCapacity); List oldKeys = _keys; List oldValues = _values; - _keys = new List(newCapacity); - _values = new List(newCapacity); + _keys = new List.fixedLength(newCapacity); + _values = new List.fixedLength(newCapacity); for (int i = 0; i < capacity; i++) { // [key] can be either of type [K] or [_DeletedKeySentinel]. Object key = oldKeys[i]; @@ -351,54 +352,93 @@ class _HashMapImpl implements HashMap { } void forEach(void f(K key, V value)) { - int length = _keys.length; - for (int i = 0; i < length; i++) { - var key = _keys[i]; - if ((key != null) && (!identical(key, _DELETED_KEY))) { - f(key, _values[i]); - } + Iterator it = new _HashMapImplIndexIterator(this); + while (it.moveNext()) { + f(_keys[it.current], _values[it.current]); } } + Iterable get keys => new _HashMapImplKeyIterable(this); - Collection get keys { - List list = new List(length); - int i = 0; - forEach((K key, V value) { - list[i++] = key; - }); - return list; - } - - Collection get values { - List list = new List(length); - int i = 0; - forEach((K key, V value) { - list[i++] = value; - }); - return list; - } + Iterable get values => new _HashMapImplValueIterable(this); bool containsKey(K key) { return (_probeForLookup(key) != -1); } - bool containsValue(V value) { - int length = _values.length; - for (int i = 0; i < length; i++) { - var key = _keys[i]; - if ((key != null) && (!identical(key, _DELETED_KEY))) { - if (_values[i] == value) return true; - } - } - return false; - } + bool containsValue(V value) => values.contains(value); String toString() { return Maps.mapToString(this); } } +class _HashMapImplKeyIterable extends Iterable { + final _HashMapImpl _map; + _HashMapImplKeyIterable(this._map); + + Iterator get iterator => new _HashMapImplKeyIterator(_map); +} + +class _HashMapImplValueIterable extends Iterable { + final _HashMapImpl _map; + _HashMapImplValueIterable(this._map); + + Iterator get iterator => new _HashMapImplValueIterator(_map); +} + +abstract class _HashMapImplIterator implements Iterator { + final _HashMapImpl _map; + int _index = -1; + E _current; + + _HashMapImplIterator(this._map); + + E _computeCurrentFromIndex(int index, List keys, List values); + + bool moveNext() { + int length = _map._keys.length; + int newIndex = _index + 1; + while (newIndex < length) { + var key = _map._keys[newIndex]; + if ((key != null) && (!identical(key, _HashMapImpl._DELETED_KEY))) { + _current = _computeCurrentFromIndex(newIndex, _map._keys, _map._values); + _index = newIndex; + return true; + } + newIndex++; + } + _index = length; + _current = null; + return false; + } + + E get current => _current; +} + +class _HashMapImplKeyIterator extends _HashMapImplIterator { + _HashMapImplKeyIterator(_HashMapImpl map) : super(map); + + E _computeCurrentFromIndex(int index, List keys, List values) { + return keys[index]; + } +} + +class _HashMapImplValueIterator extends _HashMapImplIterator { + _HashMapImplValueIterator(_HashMapImpl map) : super(map); + + E _computeCurrentFromIndex(int index, List keys, List values) { + return values[index]; + } +} + +class _HashMapImplIndexIterator extends _HashMapImplIterator { + _HashMapImplIndexIterator(_HashMapImpl map) : super(map); + + int _computeCurrentFromIndex(int index, List keys, List values) { + return index; + } +} /** * A singleton sentinel used to represent when a key is deleted from the map. @@ -473,25 +513,15 @@ class _LinkedHashMapImpl implements LinkedHashMap { return value; } - Collection get keys { - List list = new List(length); - int index = 0; - _list.forEach((_KeyValuePair entry) { - list[index++] = entry.key; - }); - assert(index == length); - return list; + Iterable get keys { + return new MappedIterable<_KeyValuePair, K>( + _list, (_KeyValuePair entry) => entry.key); } - Collection get values { - List list = new List(length); - int index = 0; - _list.forEach((_KeyValuePair entry) { - list[index++] = entry.value; - }); - assert(index == length); - return list; + Iterable get values { + return new MappedIterable<_KeyValuePair, V>( + _list, (_KeyValuePair entry) => entry.value); } void forEach(void f(K key, V value)) { @@ -505,7 +535,7 @@ class _LinkedHashMapImpl implements LinkedHashMap { } bool containsValue(V value) { - return _list.some((_KeyValuePair entry) { + return _list.any((_KeyValuePair entry) { return (entry.value == value); }); } @@ -527,3 +557,4 @@ class _LinkedHashMapImpl implements LinkedHashMap { return Maps.mapToString(this); } } + diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart index a1ff2474aa8..b5e42cbbf82 100644 --- a/sdk/lib/core/num.dart +++ b/sdk/lib/core/num.dart @@ -27,9 +27,11 @@ abstract class num implements Comparable { * Truncating division operator. * * The result of the truncating division [:a ~/ b:] is equivalent to - * [:(a / b).truncate():]. + * [:(a / b).truncate().toInt():]. */ - num operator ~/(num other); + // TODO(floitsch): this is currently not true: bignum1 / bignum2 will return + // NaN, whereas bignum1 ~/ bignum2 will give the correct result. + int operator ~/(num other); /** Negate operator. */ num operator -(); @@ -78,6 +80,13 @@ abstract class num implements Comparable { */ num truncate(); + /** + * Clamps [this] to be in the range [lowerLimit]-[upperLimit]. The comparison + * is done using [compareTo] and therefore takes [:-0.0:] into account. + * It also implies that [double.NaN] is treated as the maximal double value. + */ + num clamp(num lowerLimit, num upperLimit); + /** Truncates this [num] to an integer and returns the result as an [int]. */ int toInt(); @@ -91,32 +100,32 @@ abstract class num implements Comparable { double toDouble(); /** - * Converts a [num] to a string representation with [fractionDigits] - * digits after the decimal point. + * Converts [this] to a string representation with [fractionDigits] digits + * after the decimal point. + * + * The parameter [fractionDigits] must be an integer satisfying: + * [:0 <= fractionDigits <= 20:]. */ String toStringAsFixed(int fractionDigits); /** - * Converts a [num] to a string in decimal exponential notation with + * Converts [this] to a string in decimal exponential notation with * [fractionDigits] digits after the decimal point. + * + * If [fractionDigits] is given then it must be an integer satisfying: + * [:0 <= fractionDigits <= 20:]. Without the parameter the returned string + * uses the shortest number of digits that accurately represent [this]. */ - String toStringAsExponential(int fractionDigits); + String toStringAsExponential([int fractionDigits]); /** - * Converts a [num] to a string representation with [precision] - * significant digits. + * Converts [this] to a string representation with [precision] significant + * digits. + * + * The parameter [precision] must be an integer satisfying: + * [:1 <= precision <= 21:]. */ String toStringAsPrecision(int precision); - /** - * Converts a [num] to a string representation in the given [radix]. - * - * The [num] in converted to an [int] using [toInt]. That [int] is - * then converted to a string representation with the given - * [radix]. In the string representation, lower-case letters are - * used for digits above '9'. - * - * The [radix] argument must be an integer between 2 and 36. - */ - String toRadixString(int radix); + } diff --git a/sdk/lib/core/queue.dart b/sdk/lib/core/queue.dart index e7a97636fbd..9a000c34143 100644 --- a/sdk/lib/core/queue.dart +++ b/sdk/lib/core/queue.dart @@ -50,22 +50,10 @@ abstract class Queue extends Collection { void add(E value); /** - * Adds all elements of [collection] at the end of the queue. The - * length of the queue is extended by the length of [collection]. + * Adds all elements of [iterable] at the end of the queue. The + * length of the queue is extended by the length of [iterable]. */ - void addAll(Collection collection); - - /** - * Returns the first element of the queue. Throws an - * [StateError] exception if this queue is empty. - */ - E get first; - - /** - * Returns the last element of the queue. Throws an - * [StateError] exception if this queue is empty. - */ - E get last; + void addAll(Iterable iterable); /** * Removes all elements in the queue. The size of the queue becomes zero. @@ -172,7 +160,7 @@ class _DoubleLinkedQueueEntrySentinel extends DoubleLinkedQueueEntry { * WARNING: This class is temporary located in dart:core. It'll be removed * at some point in the near future. */ -class DoubleLinkedQueue implements Queue { +class DoubleLinkedQueue extends Iterable implements Queue { _DoubleLinkedQueueEntrySentinel _sentinel; DoubleLinkedQueue() { @@ -199,8 +187,8 @@ class DoubleLinkedQueue implements Queue { addLast(value); } - void addAll(Collection collection) { - for (final e in collection) { + void addAll(Iterable iterable) { + for (final e in iterable) { add(e); } } @@ -221,6 +209,14 @@ class DoubleLinkedQueue implements Queue { return _sentinel._previous.element; } + E get single { + // Note that this also covers the case where the queue is empty. + if (identical(_sentinel._next, _sentinel._previous)) { + return _sentinel._next.element; + } + throw new StateError("More than one element"); + } + DoubleLinkedQueueEntry lastEntry() { return _sentinel.previousEntry(); } @@ -229,12 +225,6 @@ class DoubleLinkedQueue implements Queue { return _sentinel.nextEntry(); } - int get length { - int counter = 0; - forEach((E element) { counter++; }); - return counter; - } - bool get isEmpty { return (identical(_sentinel._next, _sentinel)); } @@ -244,15 +234,6 @@ class DoubleLinkedQueue implements Queue { _sentinel._previous = _sentinel; } - void forEach(void f(E element)) { - DoubleLinkedQueueEntry entry = _sentinel._next; - while (!identical(entry, _sentinel)) { - DoubleLinkedQueueEntry nextEntry = entry._next; - f(entry._element); - entry = nextEntry; - } - } - void forEachEntry(void f(DoubleLinkedQueueEntry element)) { DoubleLinkedQueueEntry entry = _sentinel._next; while (!identical(entry, _sentinel)) { @@ -262,54 +243,7 @@ class DoubleLinkedQueue implements Queue { } } - bool every(bool f(E element)) { - DoubleLinkedQueueEntry entry = _sentinel._next; - while (!identical(entry, _sentinel)) { - DoubleLinkedQueueEntry nextEntry = entry._next; - if (!f(entry._element)) return false; - entry = nextEntry; - } - return true; - } - - bool some(bool f(E element)) { - DoubleLinkedQueueEntry entry = _sentinel._next; - while (!identical(entry, _sentinel)) { - DoubleLinkedQueueEntry nextEntry = entry._next; - if (f(entry._element)) return true; - entry = nextEntry; - } - return false; - } - - Queue map(f(E element)) { - Queue other = new Queue(); - DoubleLinkedQueueEntry entry = _sentinel._next; - while (!identical(entry, _sentinel)) { - DoubleLinkedQueueEntry nextEntry = entry._next; - other.addLast(f(entry._element)); - entry = nextEntry; - } - return other; - } - - dynamic reduce(dynamic initialValue, - dynamic combine(dynamic previousValue, E element)) { - return Collections.reduce(this, initialValue, combine); - } - - Queue filter(bool f(E element)) { - Queue other = new Queue(); - DoubleLinkedQueueEntry entry = _sentinel._next; - while (!identical(entry, _sentinel)) { - DoubleLinkedQueueEntry nextEntry = entry._next; - if (f(entry._element)) other.addLast(entry._element); - entry = nextEntry; - } - return other; - } - - _DoubleLinkedQueueIterator iterator() { + _DoubleLinkedQueueIterator get iterator { return new _DoubleLinkedQueueIterator(_sentinel); } @@ -319,22 +253,29 @@ class DoubleLinkedQueue implements Queue { } class _DoubleLinkedQueueIterator implements Iterator { - final _DoubleLinkedQueueEntrySentinel _sentinel; - DoubleLinkedQueueEntry _currentEntry; + _DoubleLinkedQueueEntrySentinel _sentinel; + DoubleLinkedQueueEntry _currentEntry = null; + E _current; - _DoubleLinkedQueueIterator(_DoubleLinkedQueueEntrySentinel this._sentinel) { - _currentEntry = _sentinel; - } + _DoubleLinkedQueueIterator(_DoubleLinkedQueueEntrySentinel sentinel) + : _sentinel = sentinel, _currentEntry = sentinel; - bool get hasNext { - return !identical(_currentEntry._next, _sentinel); - } - - E next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + // When [_currentEntry] it is set to [:null:] then it is at the end. + if (_currentEntry == null) { + assert(_current == null); + return false; } _currentEntry = _currentEntry._next; - return _currentEntry.element; + if (identical(_currentEntry, _sentinel)) { + _currentEntry = null; + _current = null; + _sentinel = null; + return false; + } + _current = _currentEntry.element; + return true; } + + E get current => _current; } diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart index 1bf1b55ea72..a85b0ffb9b3 100644 --- a/sdk/lib/core/regexp.dart +++ b/sdk/lib/core/regexp.dart @@ -62,7 +62,7 @@ abstract class Match { String get str; /** - * The pattern to search for in [str]. + * The pattern used to search in [str]. */ Pattern get pattern; } @@ -93,10 +93,10 @@ abstract class Match { abstract class RegExp implements Pattern { /** * Constructs a regular expression. The default implementation of a - * [RegExp] sets [multiLine] and [ignoreCase] to false. + * [RegExp] sets [multiLine] to false and [caseSensitive] to true. */ external factory RegExp(String pattern, {bool multiLine: false, - bool ignoreCase: false}); + bool caseSensitive: true}); /** * Searches for the first match of the regular expression @@ -129,10 +129,10 @@ abstract class RegExp implements Pattern { /** * Whether this regular expression matches multiple lines. */ - bool get multiLine; + bool get isMultiLine; /** * Whether this regular expression is case insensitive. */ - bool get ignoreCase; + bool get isCaseSensitive; } diff --git a/sdk/lib/core/sequences.dart b/sdk/lib/core/sequences.dart deleted file mode 100644 index ae0a38cdd96..00000000000 --- a/sdk/lib/core/sequences.dart +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2012, 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. - -part of dart.core; - -/** - * An indexed sequence of elements of the same type. - * - * This is a primitive interface that any finite integer-indexable - * sequence can implement. - * It is intended for data structures where access by index is - * the most efficient way to access the data. - */ -abstract class Sequence { - /** - * The limit of valid indices of the sequence. - * - * The length getter should be efficient. - */ - int get length; - - /** - * Returns the value at the given [index]. - * - * Valid indices must be in the range [:0..length - 1:]. - * The lookup operator should be efficient. - */ - E operator[](int index); -} - -/** - * A skeleton class for a [Collection] that is also a [Sequence]. - */ -abstract class SequenceCollection implements Collection, Sequence { - // The class is intended for use as a mixin as well. - - Iterator iterator() => new SequenceIterator(sequence); - - void forEach(f(E element)) { - for (int i = 0; i < this.length; i++) f(this[i]); - } - - Collection map(f(E element)) { - List result = new List(); - for (int i = 0; i < this.length; i++) { - result.add(f(this[i])); - } - return result; - } - - bool contains(E value) { - for (int i = 0; i < sequence.length; i++) { - if (sequence[i] == value) return true; - } - return false; - } - - reduce(initialValue, combine(previousValue, E element)) { - var value = initialValue; - for (int i = 0; i < this.length; i++) { - value = combine(value, this[i]); - } - return value; - } - - Collection filter(bool f(E element)) { - List result = []; - for (int i = 0; i < this.length; i++) { - E element = this[i]; - if (f(element)) result.add(element); - } - return result; - } - - bool every(bool f(E element)) { - for (int i = 0; i < this.length; i++) { - if (!f(this[i])) return false; - } - return true; - } - - bool some(bool f(E element)) { - for (int i = 0; i < this.length; i++) { - if (f(this[i])) return true; - } - return false; - } - - bool get isEmpty { - return this.length == 0; - } -} - - -/** - * An unmodifiable [List] backed by a [Sequence]. - */ -class SequenceList extends SequenceCollection implements List { - Sequence sequence; - SequenceList(this.sequence); - - int get length => sequence.length; - - E operator[](int index) => sequence[index]; - - int indexOf(E value, [int start = 0]) { - for (int i = start; i < sequence.length; i++) { - if (sequence[i] == value) return i; - } - return -1; - } - - int lastIndexOf(E value, [int start]) { - if (start == null) start = sequence.length - 1; - for (int i = start; i >= 0; i--) { - if (sequence[i] == value) return i; - } - return -1; - } - - E get first => sequence[0]; - E get last => sequence[sequence.length - 1]; - - List getRange(int start, int length) { - List result = []; - for (int i = 0; i < length; i++) { - result.add(sequence[start + i]); - } - return result; - } - - void operator []=(int index, E value) { - throw new UnsupportedError( - "Cannot modify an unmodifiable list"); - } - - void set length(int newLength) { - throw new UnsupportedError( - "Cannot change the length of an unmodifiable list"); - } - - void add(E value) { - throw new UnsupportedError( - "Cannot add to an unmodifiable list"); - } - - void addLast(E value) { - throw new UnsupportedError( - "Cannot add to an unmodifiable list"); - } - - void addAll(Collection collection) { - throw new UnsupportedError( - "Cannot add to an unmodifiable list"); - } - - void sort([int compare(E a, E b)]) { - throw new UnsupportedError( - "Cannot modify an unmodifiable list"); - } - - void clear() { - throw new UnsupportedError( - "Cannot clear an unmodifiable list"); - } - - E removeAt(int index) { - throw new UnsupportedError( - "Cannot remove in an unmodifiable list"); - } - - E removeLast() { - throw new UnsupportedError( - "Cannot remove in an unmodifiable list"); - } - - void setRange(int start, int length, List from, [int startFrom]) { - throw new UnsupportedError( - "Cannot modify an unmodifiable list"); - } - - void removeRange(int start, int length) { - throw new UnsupportedError( - "Cannot remove in an unmodifiable list"); - } - - void insertRange(int start, int length, [E initialValue]) { - throw new UnsupportedError( - "Cannot insert range in an unmodifiable list"); - } -} - -/** - * Iterates over a [Sequence] in growing index order. - */ -class SequenceIterator implements Iterator { - Sequence _sequence; - int _position; - SequenceIterator(this._sequence) : _position = 0; - bool get hasNext => _position < _sequence.length; - E next() { - if (hasNext) return _sequence[_position++]; - throw new StateError("No more elements"); - } -} - diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart index 111d2a9b18a..95a633a447c 100644 --- a/sdk/lib/core/set.dart +++ b/sdk/lib/core/set.dart @@ -35,14 +35,14 @@ abstract class Set extends Collection { bool remove(E value); /** - * Adds all the elements of the given collection to the set. + * Adds all the elements of the given [iterable] to the set. */ - void addAll(Collection collection); + void addAll(Iterable iterable); /** * Removes all the elements of the given collection from the set. */ - void removeAll(Collection collection); + void removeAll(Iterable iterable); /** * Returns true if [collection] contains all the elements of this @@ -79,7 +79,7 @@ abstract class HashSet extends Set { } -class _HashSetImpl implements HashSet { +class _HashSetImpl extends Iterable implements HashSet { _HashSetImpl() { _backingMap = new _HashMapImpl(); @@ -111,10 +111,10 @@ class _HashSetImpl implements HashSet { return true; } - void addAll(Collection collection) { - collection.forEach((E value) { - add(value); - }); + void addAll(Iterable iterable) { + for (E element in iterable) { + add(element); + } } Set intersection(Collection collection) { @@ -129,10 +129,10 @@ class _HashSetImpl implements HashSet { return new Set.from(other).containsAll(this); } - void removeAll(Collection collection) { - collection.forEach((E value) { + void removeAll(Iterable iterable) { + for (E value in iterable) { remove(value); - }); + } } bool containsAll(Collection collection) { @@ -147,37 +147,6 @@ class _HashSetImpl implements HashSet { }); } - Set map(f(E element)) { - Set result = new Set(); - _backingMap.forEach((E key, E value) { - result.add(f(key)); - }); - return result; - } - - dynamic reduce(dynamic initialValue, - dynamic combine(dynamic previousValue, E element)) { - return Collections.reduce(this, initialValue, combine); - } - - Set filter(bool f(E element)) { - Set result = new Set(); - _backingMap.forEach((E key, E value) { - if (f(key)) result.add(key); - }); - return result; - } - - bool every(bool f(E element)) { - Collection keys = _backingMap.keys; - return keys.every(f); - } - - bool some(bool f(E element)) { - Collection keys = _backingMap.keys; - return keys.some(f); - } - bool get isEmpty { return _backingMap.isEmpty; } @@ -186,9 +155,7 @@ class _HashSetImpl implements HashSet { return _backingMap.length; } - Iterator iterator() { - return new _HashSetIterator(this); - } + Iterator get iterator => new _HashSetIterator(this); String toString() { return Collections.collectionToString(this); @@ -202,48 +169,27 @@ class _HashSetImpl implements HashSet { class _HashSetIterator implements Iterator { - // TODO(4504458): Replace set_ with set. - _HashSetIterator(_HashSetImpl set_) - : _nextValidIndex = -1, - _entries = set_._backingMap._keys { - _advance(); - } + _HashSetIterator(_HashSetImpl set) + : _keysIterator = set._backingMap._keys.iterator; - bool get hasNext { - if (_nextValidIndex >= _entries.length) return false; - if (identical(_entries[_nextValidIndex], _HashMapImpl._DELETED_KEY)) { - // This happens in case the set was modified in the meantime. - // A modification on the set may make this iterator misbehave, - // but we should never return the sentinel. - _advance(); + E get current { + var result = _keysIterator.current; + if (identical(result, _HashMapImpl._DELETED_KEY)) { + // TODO(floitsch): improve the error reporting. + throw new StateError("Concurrent modification."); } - return _nextValidIndex < _entries.length; + return result; } - E next() { - if (!hasNext) { - throw new StateError("No more elements"); - } - E res = _entries[_nextValidIndex]; - _advance(); - return res; - } - - void _advance() { - int length = _entries.length; - var entry; - final deletedKey = _HashMapImpl._DELETED_KEY; + bool moveNext() { + bool result; do { - if (++_nextValidIndex >= length) break; - entry = _entries[_nextValidIndex]; - } while ((entry == null) || identical(entry, deletedKey)); + result = _keysIterator.moveNext(); + } while (result && + (_keysIterator.current == null || + identical(_keysIterator.current, _HashMapImpl._DELETED_KEY))); + return result; } - // The entries in the set. May contain null or the sentinel value. - List _entries; - - // The next valid index in [_entries] or the length of [entries_]. - // If it is the length of [_entries], calling [hasNext] on the - // iterator will return false. - int _nextValidIndex; + Iterator _keysIterator; } diff --git a/sdk/lib/core/sink.dart b/sdk/lib/core/sink.dart new file mode 100644 index 00000000000..ef1c2aa686b --- /dev/null +++ b/sdk/lib/core/sink.dart @@ -0,0 +1,40 @@ +// Copyright (c) 2012, 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. + +/** + * An interface for an object that can receive a sequence of values. + */ +abstract class Sink { + /** Write a value to the sink. */ + add(T value); + /** Tell the sink that no further values will be written. */ + void close(); +} + +// ---------------------------------------------------------------------- +// Collections/Sink interoperability +// ---------------------------------------------------------------------- + +typedef void _CollectionSinkCallback(Collection collection); + +/** Sink that stores incoming data in a collection. */ +class CollectionSink implements Sink { + final Collection collection; + final _CollectionSinkCallback callback; + bool _isClosed = false; + + CollectionSink(this.collection, [void callback(Collection collection)]) + : this.callback = callback; + + add(T value) { + if (_isClosed) throw new StateError("Adding to closed sink"); + collection.add(value); + } + + void close() { + if (_isClosed) throw new StateError("Closing closed sink"); + _isClosed = true; + if (callback != null) callback(collection); + } +} diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart index e4b4c73e6dc..7f2dcbd48b4 100644 --- a/sdk/lib/core/string.dart +++ b/sdk/lib/core/string.dart @@ -10,12 +10,24 @@ part of dart.core; * scalar character codes accessible through the [charCodeAt] or the * [charCodes] method. */ -abstract class String implements Comparable, Pattern, Sequence { +abstract class String implements Comparable, Pattern { /** * Allocates a new String for the specified [charCodes]. */ external factory String.fromCharCodes(List charCodes); + /** + * Allocates a new String for the specified [charCode]. + * + * The built string is of [length] one, if the [charCode] lies inside the + * basic multilingual plane (plane 0). Otherwise the [length] is 2 and + * the code units form a surrogate pair. + */ + factory String.character(int charCode) { + List charCodes = new List.fixedLength(1, fill: charCode); + return new String.fromCharCodes(charCodes); + } + /** * Gets the character (as [String]) at the given [index]. */ @@ -71,6 +83,22 @@ abstract class String implements Comparable, Pattern, Sequence { */ String concat(String other); + /** + * Returns a slice of this string from [startIndex] to [endIndex]. + * + * If [startIndex] is omitted, it defaults to the start of the string. + * + * If [endIndex] is omitted, it defaults to the end of the string. + * + * If either index is negative, it's taken as a negative index from the + * end of the string. Their effective value is computed by adding the + * negative value to the [length] of the string. + * + * The effective indices, after must be non-negative, no greater than the + * length of the string, and [endIndex] must not be less than [startIndex]. + */ + String slice([int startIndex, int endIndex]); + /** * Returns a substring of this string in the given range. * [startIndex] is inclusive and [endIndex] is exclusive. @@ -102,9 +130,19 @@ abstract class String implements Comparable, Pattern, Sequence { /** * Returns a new string where all occurences of [from] in this string - * are replaced with [to]. + * are replaced with [replace]. */ - String replaceAll(Pattern from, String to); + String replaceAll(Pattern from, var replace); + + /** + * Returns a new string where all occurences of [from] in this string + * are replaced with a [String] depending on [replace]. + * + * + * The [replace] function is called with the [Match] generated + * by the pattern, and its result is used as replacement. + */ + String replaceAllMapped(Pattern from, String replace(Match match)); /** * Splits the string around matches of [pattern]. Returns @@ -117,6 +155,23 @@ abstract class String implements Comparable, Pattern, Sequence { */ List splitChars(); + /** + * Splits the string on the [pattern], then converts each part and each match. + * + * The pattern is used to split the string into parts and separating matches. + * + * Each match is converted to a string by calling [onMatch]. If [onMatch] + * is omitted, the matched string is used. + * + * Each non-matched part is converted by a call to [onNonMatch]. If + * [onNonMatch] is omitted, the non-matching part is used. + * + * Then all the converted parts are combined into the resulting string. + */ + String splitMapJoin(Pattern pattern, + {String onMatch(Match match), + String onNonMatch(String nonMatch)}); + /** * Returns a list of the scalar character codes of this string. */ diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart index fda711180b8..71bf31d2a00 100644 --- a/sdk/lib/core/string_buffer.dart +++ b/sdk/lib/core/string_buffer.dart @@ -27,7 +27,7 @@ abstract class StringBuffer { void addCharCode(int charCode); /// Adds all items in [objects] to the buffer. - void addAll(Collection objects); + void addAll(Iterable objects); /// Clears the string buffer. void clear(); @@ -66,7 +66,7 @@ class _StringBufferImpl implements StringBuffer { } /// Adds all items in [objects] to the buffer. - void addAll(Collection objects) { + void addAll(Iterable objects) { for (Object obj in objects) add(obj); } diff --git a/sdk/lib/core/strings.dart b/sdk/lib/core/strings.dart index 9d565a1e22a..dcdcafc4cfc 100644 --- a/sdk/lib/core/strings.dart +++ b/sdk/lib/core/strings.dart @@ -8,10 +8,10 @@ abstract class Strings { /** * Joins all the given strings to create a new string. */ - external static String join(List strings, String separator); + external static String join(Iterable strings, String separator); /** * Concatenates all the given strings to create a new string. */ - external static String concatAll(List strings); + external static String concatAll(Iterable strings); } diff --git a/sdk/lib/crypto/crypto.dart b/sdk/lib/crypto/crypto.dart index ea4e8fee6af..590a62e9359 100644 --- a/sdk/lib/crypto/crypto.dart +++ b/sdk/lib/crypto/crypto.dart @@ -16,27 +16,28 @@ part 'sha256.dart'; /** * Interface for cryptographic hash functions. * - * The [update] method is used to add data to the hash. The [digest] method + * The [add] method is used to add data to the hash. The [close] method * is used to extract the message digest. * - * Once the [digest] method has been called no more data can be added using the - * [update] method. If [update] is called after the first call to [digest] a + * Once the [close] method has been called no more data can be added using the + * [add] method. If [add] is called after the first call to [close] a * HashException is thrown. * * If multiple instances of a given Hash is needed the [newInstance] * method can provide a new instance. */ +// TODO(floitsch): make Hash implement Sink, StreamSink or similar. abstract class Hash { /** * Add a list of bytes to the hash computation. */ - Hash update(List data); + add(List data); /** * Finish the hash computation and extract the message digest as * a list of bytes. */ - List digest(); + List close(); /** * Returns a new instance of this hash function. @@ -79,9 +80,10 @@ abstract class MD5 implements Hash { /** * Hash-based Message Authentication Code support. * - * The [update] method is used to add data to the message. The [digest] method - * is used to extract the message authentication code. + * The [add] method is used to add data to the message. The [digest] and + * [close] methods are used to extract the message authentication code. */ +// TODO(floitsch): make Hash implement Sink, StreamSink or similar. abstract class HMAC { /** * Create an [HMAC] object from a [Hash] and a key. @@ -91,13 +93,18 @@ abstract class HMAC { /** * Add a list of bytes to the message. */ - HMAC update(List data); + add(List data); /** * Perform the actual computation and extract the message digest * as a list of bytes. */ - List digest(); + List close(); + + /** + * Extract the message digest as a list of bytes without closing [this]. + */ + List get digest; /** * Verify that the HMAC computed for the data so far matches the diff --git a/sdk/lib/crypto/hash_utils.dart b/sdk/lib/crypto/hash_utils.dart index 81dcd682794..ed42140f385 100644 --- a/sdk/lib/crypto/hash_utils.dart +++ b/sdk/lib/crypto/hash_utils.dart @@ -26,12 +26,12 @@ abstract class _HashBase implements Hash { int this._digestSizeInWords, bool this._bigEndianWords) : _pendingData = [] { - _currentChunk = new List(_chunkSizeInWords); - _h = new List(_digestSizeInWords); + _currentChunk = new List.fixedLength(_chunkSizeInWords); + _h = new List.fixedLength(_digestSizeInWords); } // Update the hasher with more data. - _HashBase update(List data) { + add(List data) { if (_digestCalled) { throw new HashException( 'Hash update method called after digest was retrieved'); @@ -39,11 +39,10 @@ abstract class _HashBase implements Hash { _lengthInBytes += data.length; _pendingData.addAll(data); _iterate(); - return this; } // Finish the hash computation and return the digest string. - List digest() { + List close() { if (_digestCalled) { return _resultAsBytes(); } @@ -98,7 +97,7 @@ abstract class _HashBase implements Hash { // Convert a 32-bit word to four bytes. _wordToBytes(int word) { - List bytes = new List(_BYTES_PER_WORD); + List bytes = new List.fixedLength(_BYTES_PER_WORD); bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8; bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8; bytes[2] = (word >> (_bigEndianWords ? 8 : 16)) & _MASK_8; diff --git a/sdk/lib/crypto/hmac.dart b/sdk/lib/crypto/hmac.dart index 8844704e3f2..2dd3902c27e 100644 --- a/sdk/lib/crypto/hmac.dart +++ b/sdk/lib/crypto/hmac.dart @@ -5,25 +5,28 @@ part of dart.crypto; class _HMAC implements HMAC { + bool _isClosed = false; + _HMAC(Hash this._hash, List this._key) : _message = []; - HMAC update(List data) { + add(List data) { + if (_isClosed) throw new StateError("HMAC is closed"); _message.addAll(data); - return this; } - List digest() { + List get digest { var blockSize = _hash.blockSize; // Hash the key if it is longer than the block size of the hash. if (_key.length > blockSize) { _hash = _hash.newInstance(); - _key = _hash.update(_key).digest(); + _hash.add(_key); + _key = _hash.close(); } // Zero-pad the key until its size is equal to the block size of the hash. if (_key.length < blockSize) { - var newKey = new List(blockSize); + var newKey = new List.fixedLength(blockSize); newKey.setRange(0, _key.length, _key); for (var i = _key.length; i < blockSize; i++) { newKey[i] = 0; @@ -32,14 +35,16 @@ class _HMAC implements HMAC { } // Compute inner padding. - var padding = new List(blockSize); + var padding = new List.fixedLength(blockSize); for (var i = 0; i < blockSize; i++) { padding[i] = 0x36 ^ _key[i]; } // Inner hash computation. _hash = _hash.newInstance(); - var innerHash = _hash.update(padding).update(_message).digest(); + _hash.add(padding); + _hash.add(_message); + var innerHash = _hash.close(); // Compute outer padding. for (var i = 0; i < blockSize; i++) { @@ -48,11 +53,18 @@ class _HMAC implements HMAC { // Outer hash computation which is the result. _hash = _hash.newInstance(); - return _hash.update(padding).update(innerHash).digest(); + _hash.add(padding); + _hash.add(innerHash); + return _hash.close(); + } + + List close() { + _isClosed = true; + return digest; } bool verify(List digest) { - var computedDigest = this.digest(); + var computedDigest = this.digest; if (digest.length != computedDigest.length) { throw new ArgumentError( 'Invalid digest size: ${digest.length} in HMAC.verify. ' diff --git a/sdk/lib/crypto/sha1.dart b/sdk/lib/crypto/sha1.dart index 83e9217806d..af3d35449b8 100644 --- a/sdk/lib/crypto/sha1.dart +++ b/sdk/lib/crypto/sha1.dart @@ -7,7 +7,7 @@ part of dart.crypto; // The SHA1 hasher is used to compute an SHA1 message digest. class _SHA1 extends _HashBase implements SHA1 { // Construct a SHA1 hasher object. - _SHA1() : _w = new List(80), super(16, 5, true) { + _SHA1() : _w = new List.fixedLength(80), super(16, 5, true) { _h[0] = 0x67452301; _h[1] = 0xEFCDAB89; _h[2] = 0x98BADCFE; diff --git a/sdk/lib/crypto/sha256.dart b/sdk/lib/crypto/sha256.dart index 3df0ffd0627..84dabf9bb03 100644 --- a/sdk/lib/crypto/sha256.dart +++ b/sdk/lib/crypto/sha256.dart @@ -7,7 +7,7 @@ part of dart.crypto; // The SHA256 hasher is used to compute an SHA256 message digest. class _SHA256 extends _HashBase implements SHA256 { // Construct a SHA256 hasher object. - _SHA256() : _w = new List(64), super(16, 8, true) { + _SHA256() : _w = new List.fixedLength(64), super(16, 8, true) { // Initial value of the hash parts. First 32 bits of the fractional parts // of the square roots of the first 8 prime numbers. _h[0] = 0x6a09e667; diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart index 5e169881d3a..0ba229ef20e 100644 --- a/sdk/lib/html/dart2js/html_dart2js.dart +++ b/sdk/lib/html/dart2js/html_dart2js.dart @@ -1,10 +1,11 @@ library html; +import 'dart:async'; import 'dart:collection'; import 'dart:html_common'; import 'dart:indexed_db'; import 'dart:isolate'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:math'; import 'dart:svg' as svg; import 'dart:web_audio' as web_audio; @@ -5999,7 +6000,7 @@ class Document extends Node native "*Document" final mutableMatches = $dom_getElementsByName( selectors.substring(7,selectors.length - 2)); int len = mutableMatches.length; - final copyOfMatches = new List(len); + final copyOfMatches = new List.fixedLength(len); for (int i = 0; i < len; ++i) { copyOfMatches[i] = mutableMatches[i]; } @@ -6007,7 +6008,7 @@ class Document extends Node native "*Document" } else if (new RegExp("^[*a-zA-Z0-9]+\$").hasMatch(selectors)) { final mutableMatches = $dom_getElementsByTagName(selectors); int len = mutableMatches.length; - final copyOfMatches = new List(len); + final copyOfMatches = new List.fixedLength(len); for (int i = 0; i < len; ++i) { copyOfMatches[i] = mutableMatches[i]; } @@ -6494,13 +6495,61 @@ class DomMimeTypeArray implements JavaScriptIndexingBehavior, List // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomMimeType)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(DomMimeType element) => Collections.contains(this, element); + + void forEach(void f(DomMimeType element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(DomMimeType element)) => new MappedList(this, f); + + Iterable where(bool f(DomMimeType element)) => new WhereIterable(this, f); + + bool every(bool f(DomMimeType element)) => Collections.every(this, f); + + bool any(bool f(DomMimeType element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(DomMimeType value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(DomMimeType value)) { + return new SkipWhileIterable(this, test); + } + + DomMimeType firstMatching(bool test(DomMimeType value), { DomMimeType orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + DomMimeType lastMatching(bool test(DomMimeType value), {DomMimeType orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + DomMimeType singleMatching(bool test(DomMimeType value)) { + return Collections.singleMatching(this, test); + } + + DomMimeType elementAt(int index) { + return this[index]; + } + // From Collection: void add(DomMimeType value) { @@ -6511,29 +6560,10 @@ class DomMimeTypeArray implements JavaScriptIndexingBehavior, List throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomMimeType)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(DomMimeType element) => Collections.contains(this, element); - - void forEach(void f(DomMimeType element)) => Collections.forEach(this, f); - - Collection map(f(DomMimeType element)) => Collections.map(this, [], f); - - Collection filter(bool f(DomMimeType element)) => - Collections.filter(this, [], f); - - bool every(bool f(DomMimeType element)) => Collections.every(this, f); - - bool some(bool f(DomMimeType element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -6555,9 +6585,25 @@ class DomMimeTypeArray implements JavaScriptIndexingBehavior, List return Lists.lastIndexOf(this, element, start); } - DomMimeType get first => this[0]; + DomMimeType get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - DomMimeType get last => this[length - 1]; + DomMimeType get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + DomMimeType get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + DomMimeType min([int compare(DomMimeType a, DomMimeType b)]) => _Collections.minInList(this, compare); + + DomMimeType max([int compare(DomMimeType a, DomMimeType b)]) => _Collections.maxInList(this, compare); DomMimeType removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -6652,13 +6698,61 @@ class DomPluginArray implements JavaScriptIndexingBehavior, List nati // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomPlugin)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(DomPlugin element) => Collections.contains(this, element); + + void forEach(void f(DomPlugin element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(DomPlugin element)) => new MappedList(this, f); + + Iterable where(bool f(DomPlugin element)) => new WhereIterable(this, f); + + bool every(bool f(DomPlugin element)) => Collections.every(this, f); + + bool any(bool f(DomPlugin element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(DomPlugin value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(DomPlugin value)) { + return new SkipWhileIterable(this, test); + } + + DomPlugin firstMatching(bool test(DomPlugin value), { DomPlugin orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + DomPlugin lastMatching(bool test(DomPlugin value), {DomPlugin orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + DomPlugin singleMatching(bool test(DomPlugin value)) { + return Collections.singleMatching(this, test); + } + + DomPlugin elementAt(int index) { + return this[index]; + } + // From Collection: void add(DomPlugin value) { @@ -6669,29 +6763,10 @@ class DomPluginArray implements JavaScriptIndexingBehavior, List nati throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomPlugin)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(DomPlugin element) => Collections.contains(this, element); - - void forEach(void f(DomPlugin element)) => Collections.forEach(this, f); - - Collection map(f(DomPlugin element)) => Collections.map(this, [], f); - - Collection filter(bool f(DomPlugin element)) => - Collections.filter(this, [], f); - - bool every(bool f(DomPlugin element)) => Collections.every(this, f); - - bool some(bool f(DomPlugin element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -6713,9 +6788,25 @@ class DomPluginArray implements JavaScriptIndexingBehavior, List nati return Lists.lastIndexOf(this, element, start); } - DomPlugin get first => this[0]; + DomPlugin get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - DomPlugin get last => this[length - 1]; + DomPlugin get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + DomPlugin get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + DomPlugin min([int compare(DomPlugin a, DomPlugin b)]) => _Collections.minInList(this, compare); + + DomPlugin max([int compare(DomPlugin a, DomPlugin b)]) => _Collections.maxInList(this, compare); DomPlugin removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -6869,13 +6960,61 @@ class DomStringList implements JavaScriptIndexingBehavior, List native " // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { + return Collections.reduce(this, initialValue, combine); + } + + // contains() defined by IDL. + + void forEach(void f(String element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(String element)) => new MappedList(this, f); + + Iterable where(bool f(String element)) => new WhereIterable(this, f); + + bool every(bool f(String element)) => Collections.every(this, f); + + bool any(bool f(String element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(String value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(String value)) { + return new SkipWhileIterable(this, test); + } + + String firstMatching(bool test(String value), { String orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + String lastMatching(bool test(String value), {String orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + String singleMatching(bool test(String value)) { + return Collections.singleMatching(this, test); + } + + String elementAt(int index) { + return this[index]; + } + // From Collection: void add(String value) { @@ -6886,29 +7025,10 @@ class DomStringList implements JavaScriptIndexingBehavior, List native " throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { - return Collections.reduce(this, initialValue, combine); - } - - // contains() defined by IDL. - - void forEach(void f(String element)) => Collections.forEach(this, f); - - Collection map(f(String element)) => Collections.map(this, [], f); - - Collection filter(bool f(String element)) => - Collections.filter(this, [], f); - - bool every(bool f(String element)) => Collections.every(this, f); - - bool some(bool f(String element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -6930,9 +7050,25 @@ class DomStringList implements JavaScriptIndexingBehavior, List native " return Lists.lastIndexOf(this, element, start); } - String get first => this[0]; + String get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - String get last => this[length - 1]; + String get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + String get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + String min([int compare(String a, String b)]) => _Collections.minInList(this, compare); + + String max([int compare(String a, String b)]) => _Collections.maxInList(this, compare); String removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -7012,14 +7148,22 @@ class _ChildrenElementList implements List { : _childElements = element.$dom_children, _element = element; - List _toList() { - final output = new List(_childElements.length); + List toList() { + final output = new List.fixedLength(_childElements.length); for (int i = 0, len = _childElements.length; i < len; i++) { output[i] = _childElements[i]; } return output; } + Set toSet() { + final output = new Set(_childElements.length); + for (int i = 0, len = _childElements.length; i < len; i++) { + output.add(_childElements[i]); + } + return output; + } + bool contains(Element element) => _childElements.contains(element); void forEach(void f(Element element)) { @@ -7028,46 +7172,71 @@ class _ChildrenElementList implements List { } } - List filter(bool f(Element element)) { - final output = []; - forEach((Element element) { - if (f(element)) { - output.add(element); - } - }); - return new _FrozenElementList._wrap(output); - } - bool every(bool f(Element element)) { for (Element element in this) { if (!f(element)) { return false; } - }; + } return true; } - bool some(bool f(Element element)) { + bool any(bool f(Element element)) { for (Element element in this) { if (f(element)) { return true; } - }; + } return false; } - Collection map(f(Element element)) { - final out = []; - for (Element el in this) { - out.add(f(el)); - } - return out; + String join([String separator]) { + return Collections.joinList(this, separator); } + List mappedBy(f(Element element)) { + return new MappedList(this, f); + } + + Iterable where(bool f(Element element)) + => new WhereIterable(this, f); + bool get isEmpty { return _element.$dom_firstElementChild == null; } + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(Element value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(Element value)) { + return new SkipWhileIterable(this, test); + } + + Element firstMatching(bool test(Element value), {Element orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Element singleMatching(bool test(Element value)) { + return Collections.singleMatching(this, test); + } + + Element elementAt(int index) { + return this[index]; + } + int get length { return _childElements.length; } @@ -7092,10 +7261,10 @@ class _ChildrenElementList implements List { Element addLast(Element value) => add(value); - Iterator iterator() => _toList().iterator(); + Iterator get iterator => toList().iterator; - void addAll(Collection collection) { - for (Element element in collection) { + void addAll(Iterable iterable) { + for (Element element in iterable) { _element.$dom_appendChild(element); } } @@ -7156,12 +7325,29 @@ class _ChildrenElementList implements List { } Element get first { - return _element.$dom_firstElementChild; + Element result = _element.$dom_firstElementChild; + if (result == null) throw new StateError("No elements"); + return result; } Element get last { - return _element.$dom_lastElementChild; + Element result = _element.$dom_lastElementChild; + if (result == null) throw new StateError("No elements"); + return result; + } + + Element get single { + if (length > 1) throw new StateError("More than one element"); + return first; + } + + Element min([int compare(Element a, Element b)]) { + return _Collections.minInList(this, compare); + } + + Element max([int compare(Element a, Element b)]) { + return _Collections.maxInList(this, compare); } } @@ -7187,22 +7373,17 @@ class _FrozenElementList implements List { } } - Collection map(f(Element element)) { - final out = []; - for (Element el in this) { - out.add(f(el)); - } - return out; + String join([String separator]) { + return Collections.joinList(this, separator); } - List filter(bool f(Element element)) { - final out = []; - for (Element el in this) { - if (f(el)) out.add(el); - } - return out; + List mappedBy(f(Element element)) { + return new MappedList(this, f); } + Iterable where(bool f(Element element)) + => new WhereIterable(this, f); + bool every(bool f(Element element)) { for(Element element in this) { if (!f(element)) { @@ -7212,7 +7393,7 @@ class _FrozenElementList implements List { return true; } - bool some(bool f(Element element)) { + bool any(bool f(Element element)) { for(Element element in this) { if (f(element)) { return true; @@ -7221,6 +7402,38 @@ class _FrozenElementList implements List { return false; } + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(T value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(T value)) { + return new SkipWhileIterable(this, test); + } + + Element firstMatching(bool test(Element value), {Element orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Element singleMatching(bool test(Element value)) { + return Collections.singleMatching(this, test); + } + + Element elementAt(int index) { + return this[index]; + } + bool get isEmpty => _nodeList.isEmpty; int get length => _nodeList.length; @@ -7243,9 +7456,9 @@ class _FrozenElementList implements List { throw new UnsupportedError(''); } - Iterator iterator() => new _FrozenElementListIterator(this); + Iterator get iterator => new _FrozenElementListIterator(this); - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError(''); } @@ -7294,6 +7507,16 @@ class _FrozenElementList implements List { Element get first => _nodeList.first; Element get last => _nodeList.last; + + Element get single => _nodeList.single; + + Element min([int compare(Element a, Element b)]) { + return _Collections.minInList(this, compare); + } + + Element max([int compare(Element a, Element b)]) { + return _Collections.maxInList(this, compare); + } } class _FrozenElementListIterator implements Iterator { @@ -7303,21 +7526,28 @@ class _FrozenElementListIterator implements Iterator { _FrozenElementListIterator(this._list); /** - * Gets the next element in the iteration. Throws a - * [StateError("No more elements")] if no element is left. + * Moves to the next element. Returns true if the iterator is positioned + * at an element. Returns false if it is positioned after the last element. */ - Element next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextIndex = _index + 1; + if (nextIndex < _list.length) { + _current = _list[nextIndex]; + _index = nextIndex; + return true; } - - return _list[_index++]; + _index = _list.length; + _current = null; + return false; } /** - * Returns whether the [Iterator] has elements left. + * Returns the element the [Iterator] is positioned at. + * + * Return [:null:] if the iterator is positioned before the first, or + * after the last element. */ - bool get hasNext => _index < _list.length; + E get current => _current; } class _ElementCssClassSet extends CssClassSet { @@ -7341,7 +7571,7 @@ class _ElementCssClassSet extends CssClassSet { void writeClasses(Set s) { List list = new List.from(s); - _element.$dom_className = Strings.join(list, ' '); + _element.$dom_className = s.join(' '); } } @@ -8847,13 +9077,61 @@ class FileList implements JavaScriptIndexingBehavior, List native "*FileLi // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, File)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(File element) => Collections.contains(this, element); + + void forEach(void f(File element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(File element)) => new MappedList(this, f); + + Iterable where(bool f(File element)) => new WhereIterable(this, f); + + bool every(bool f(File element)) => Collections.every(this, f); + + bool any(bool f(File element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(File value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(File value)) { + return new SkipWhileIterable(this, test); + } + + File firstMatching(bool test(File value), { File orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + File lastMatching(bool test(File value), {File orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + File singleMatching(bool test(File value)) { + return Collections.singleMatching(this, test); + } + + File elementAt(int index) { + return this[index]; + } + // From Collection: void add(File value) { @@ -8864,29 +9142,10 @@ class FileList implements JavaScriptIndexingBehavior, List native "*FileLi throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, File)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(File element) => Collections.contains(this, element); - - void forEach(void f(File element)) => Collections.forEach(this, f); - - Collection map(f(File element)) => Collections.map(this, [], f); - - Collection filter(bool f(File element)) => - Collections.filter(this, [], f); - - bool every(bool f(File element)) => Collections.every(this, f); - - bool some(bool f(File element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -8908,9 +9167,25 @@ class FileList implements JavaScriptIndexingBehavior, List native "*FileLi return Lists.lastIndexOf(this, element, start); } - File get first => this[0]; + File get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - File get last => this[length - 1]; + File get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + File get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + File min([int compare(File a, File b)]) => _Collections.minInList(this, compare); + + File max([int compare(File a, File b)]) => _Collections.maxInList(this, compare); File removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -9223,13 +9498,61 @@ class Float32Array extends ArrayBufferView implements JavaScriptIndexingBehavior // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(num element) => Collections.contains(this, element); + + void forEach(void f(num element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(num element)) => new MappedList(this, f); + + Iterable where(bool f(num element)) => new WhereIterable(this, f); + + bool every(bool f(num element)) => Collections.every(this, f); + + bool any(bool f(num element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(num value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(num value)) { + return new SkipWhileIterable(this, test); + } + + num firstMatching(bool test(num value), { num orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + num lastMatching(bool test(num value), {num orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + num singleMatching(bool test(num value)) { + return Collections.singleMatching(this, test); + } + + num elementAt(int index) { + return this[index]; + } + // From Collection: void add(num value) { @@ -9240,29 +9563,10 @@ class Float32Array extends ArrayBufferView implements JavaScriptIndexingBehavior throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(num element) => Collections.contains(this, element); - - void forEach(void f(num element)) => Collections.forEach(this, f); - - Collection map(f(num element)) => Collections.map(this, [], f); - - Collection filter(bool f(num element)) => - Collections.filter(this, [], f); - - bool every(bool f(num element)) => Collections.every(this, f); - - bool some(bool f(num element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -9284,9 +9588,25 @@ class Float32Array extends ArrayBufferView implements JavaScriptIndexingBehavior return Lists.lastIndexOf(this, element, start); } - num get first => this[0]; + num get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - num get last => this[length - 1]; + num get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + num get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + num min([int compare(num a, num b)]) => _Collections.minInList(this, compare); + + num max([int compare(num a, num b)]) => _Collections.maxInList(this, compare); num removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -9349,13 +9669,61 @@ class Float64Array extends ArrayBufferView implements JavaScriptIndexingBehavior // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(num element) => Collections.contains(this, element); + + void forEach(void f(num element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(num element)) => new MappedList(this, f); + + Iterable where(bool f(num element)) => new WhereIterable(this, f); + + bool every(bool f(num element)) => Collections.every(this, f); + + bool any(bool f(num element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(num value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(num value)) { + return new SkipWhileIterable(this, test); + } + + num firstMatching(bool test(num value), { num orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + num lastMatching(bool test(num value), {num orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + num singleMatching(bool test(num value)) { + return Collections.singleMatching(this, test); + } + + num elementAt(int index) { + return this[index]; + } + // From Collection: void add(num value) { @@ -9366,29 +9734,10 @@ class Float64Array extends ArrayBufferView implements JavaScriptIndexingBehavior throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(num element) => Collections.contains(this, element); - - void forEach(void f(num element)) => Collections.forEach(this, f); - - Collection map(f(num element)) => Collections.map(this, [], f); - - Collection filter(bool f(num element)) => - Collections.filter(this, [], f); - - bool every(bool f(num element)) => Collections.every(this, f); - - bool some(bool f(num element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -9410,9 +9759,25 @@ class Float64Array extends ArrayBufferView implements JavaScriptIndexingBehavior return Lists.lastIndexOf(this, element, start); } - num get first => this[0]; + num get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - num get last => this[length - 1]; + num get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + num get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + num min([int compare(num a, num b)]) => _Collections.minInList(this, compare); + + num max([int compare(num a, num b)]) => _Collections.maxInList(this, compare); num removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -9835,13 +10200,61 @@ class HtmlAllCollection implements JavaScriptIndexingBehavior, List native // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -9852,29 +10265,10 @@ class HtmlAllCollection implements JavaScriptIndexingBehavior, List native throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -9896,9 +10290,25 @@ class HtmlAllCollection implements JavaScriptIndexingBehavior, List native return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -9956,13 +10366,61 @@ class HtmlCollection implements JavaScriptIndexingBehavior, List native "* // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -9973,29 +10431,10 @@ class HtmlCollection implements JavaScriptIndexingBehavior, List native "* throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -10017,9 +10456,25 @@ class HtmlCollection implements JavaScriptIndexingBehavior, List native "* return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -11582,13 +12037,61 @@ class Int16Array extends ArrayBufferView implements JavaScriptIndexingBehavior, // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -11599,29 +12102,10 @@ class Int16Array extends ArrayBufferView implements JavaScriptIndexingBehavior, throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -11643,9 +12127,25 @@ class Int16Array extends ArrayBufferView implements JavaScriptIndexingBehavior, return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -11708,13 +12208,61 @@ class Int32Array extends ArrayBufferView implements JavaScriptIndexingBehavior, // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -11725,29 +12273,10 @@ class Int32Array extends ArrayBufferView implements JavaScriptIndexingBehavior, throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -11769,9 +12298,25 @@ class Int32Array extends ArrayBufferView implements JavaScriptIndexingBehavior, return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -11834,13 +12379,61 @@ class Int8Array extends ArrayBufferView implements JavaScriptIndexingBehavior, L // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -11851,29 +12444,10 @@ class Int8Array extends ArrayBufferView implements JavaScriptIndexingBehavior, L throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -11895,9 +12469,25 @@ class Int8Array extends ArrayBufferView implements JavaScriptIndexingBehavior, L return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -13538,13 +14128,61 @@ class NamedNodeMap implements JavaScriptIndexingBehavior, List native "*Na // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -13555,29 +14193,10 @@ class NamedNodeMap implements JavaScriptIndexingBehavior, List native "*Na throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -13599,9 +14218,25 @@ class NamedNodeMap implements JavaScriptIndexingBehavior, List native "*Na return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -13778,8 +14413,30 @@ class _ChildNodeListLazy implements List { _ChildNodeListLazy(this._this); - Node get first => JS('Node', '#.firstChild', _this); - Node get last => JS('Node', '#.lastChild', _this); + Node get first { + Node result = JS('Node', '#.firstChild', _this); + if (result == null) throw new StateError("No elements"); + return result; + } + Node get last { + Node result = JS('Node', '#.lastChild', _this); + if (result == null) throw new StateError("No elements"); + return result; + } + Node get single { + int l = this.length; + if (l == 0) throw new StateError("No elements"); + if (l > 1) throw new StateError("More than one element"); + return JS('Node', '#.firstChild', _this); + } + + Node min([int compare(Node a, Node b)]) { + return _Collections.minInList(this, compare); + } + + Node max([int compare(Node a, Node b)]) { + return _Collections.maxInList(this, compare); + } void add(Node value) { _this.$dom_appendChild(value); @@ -13790,8 +14447,8 @@ class _ChildNodeListLazy implements List { } - void addAll(Collection collection) { - for (Node node in collection) { + void addAll(Iterable iterable) { + for (Node node in iterable) { _this.$dom_appendChild(node); } } @@ -13820,7 +14477,7 @@ class _ChildNodeListLazy implements List { _this.$dom_replaceChild(value, this[index]); } - Iterator iterator() => _this.$dom_childNodes.iterator(); + Iterator get iterator => _this.$dom_childNodes.iterator; // TODO(jacobr): We can implement these methods much more efficiently by // looking up the nodeList only once instead of once per iteration. @@ -13833,19 +14490,56 @@ class _ChildNodeListLazy implements List { return Collections.reduce(this, initialValue, combine); } - Collection map(f(Node element)) => Collections.map(this, [], f); + String join([String separator]) { + return Collections.joinList(this, separator); + } - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); + List mappedBy(f(Node element)) => + new MappedList(this, f); + + Iterable where(bool f(Node element)) => + new WhereIterable(this, f); bool every(bool f(Node element)) => Collections.every(this, f); - bool some(bool f(Node element)) => Collections.some(this, f); + bool any(bool f(Node element)) => Collections.any(this, f); bool get isEmpty => this.length == 0; // From List: + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), {Node orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // TODO(jacobr): this could be implemented for child node lists. // The exception we throw here is misleading. void sort([int compare(Node a, Node b)]) { @@ -14156,13 +14850,61 @@ class NodeList implements JavaScriptIndexingBehavior, List native "*NodeLi // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -14173,29 +14915,10 @@ class NodeList implements JavaScriptIndexingBehavior, List native "*NodeLi throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -14217,9 +14940,25 @@ class NodeList implements JavaScriptIndexingBehavior, List native "*NodeLi return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -15808,13 +16547,13 @@ class SelectElement extends Element native "*HTMLSelectElement" { // Override default options, since IE returns SelectElement itself and it // does not operate as a List. List get options { - return this.children.filter((e) => e is OptionElement); + return this.children.where((e) => e is OptionElement).toList(); } List get selectedOptions { // IE does not change the selected flag for single-selection items. if (this.multiple) { - return this.options.filter((o) => o.selected); + return this.options.where((o) => o.selected).toList(); } else { return [this.options[this.selectedIndex]]; } @@ -15980,13 +16719,61 @@ class SourceBufferList extends EventTarget implements JavaScriptIndexingBehavior // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SourceBuffer)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SourceBuffer element) => Collections.contains(this, element); + + void forEach(void f(SourceBuffer element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SourceBuffer element)) => new MappedList(this, f); + + Iterable where(bool f(SourceBuffer element)) => new WhereIterable(this, f); + + bool every(bool f(SourceBuffer element)) => Collections.every(this, f); + + bool any(bool f(SourceBuffer element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SourceBuffer value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SourceBuffer value)) { + return new SkipWhileIterable(this, test); + } + + SourceBuffer firstMatching(bool test(SourceBuffer value), { SourceBuffer orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SourceBuffer lastMatching(bool test(SourceBuffer value), {SourceBuffer orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SourceBuffer singleMatching(bool test(SourceBuffer value)) { + return Collections.singleMatching(this, test); + } + + SourceBuffer elementAt(int index) { + return this[index]; + } + // From Collection: void add(SourceBuffer value) { @@ -15997,29 +16784,10 @@ class SourceBufferList extends EventTarget implements JavaScriptIndexingBehavior throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SourceBuffer)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SourceBuffer element) => Collections.contains(this, element); - - void forEach(void f(SourceBuffer element)) => Collections.forEach(this, f); - - Collection map(f(SourceBuffer element)) => Collections.map(this, [], f); - - Collection filter(bool f(SourceBuffer element)) => - Collections.filter(this, [], f); - - bool every(bool f(SourceBuffer element)) => Collections.every(this, f); - - bool some(bool f(SourceBuffer element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -16041,9 +16809,25 @@ class SourceBufferList extends EventTarget implements JavaScriptIndexingBehavior return Lists.lastIndexOf(this, element, start); } - SourceBuffer get first => this[0]; + SourceBuffer get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SourceBuffer get last => this[length - 1]; + SourceBuffer get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SourceBuffer get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SourceBuffer min([int compare(SourceBuffer a, SourceBuffer b)]) => _Collections.minInList(this, compare); + + SourceBuffer max([int compare(SourceBuffer a, SourceBuffer b)]) => _Collections.maxInList(this, compare); SourceBuffer removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -16159,13 +16943,61 @@ class SpeechGrammarList implements JavaScriptIndexingBehavior, List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechGrammar)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SpeechGrammar element) => Collections.contains(this, element); + + void forEach(void f(SpeechGrammar element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SpeechGrammar element)) => new MappedList(this, f); + + Iterable where(bool f(SpeechGrammar element)) => new WhereIterable(this, f); + + bool every(bool f(SpeechGrammar element)) => Collections.every(this, f); + + bool any(bool f(SpeechGrammar element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SpeechGrammar value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SpeechGrammar value)) { + return new SkipWhileIterable(this, test); + } + + SpeechGrammar firstMatching(bool test(SpeechGrammar value), { SpeechGrammar orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SpeechGrammar lastMatching(bool test(SpeechGrammar value), {SpeechGrammar orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SpeechGrammar singleMatching(bool test(SpeechGrammar value)) { + return Collections.singleMatching(this, test); + } + + SpeechGrammar elementAt(int index) { + return this[index]; + } + // From Collection: void add(SpeechGrammar value) { @@ -16176,29 +17008,10 @@ class SpeechGrammarList implements JavaScriptIndexingBehavior, List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechGrammar)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SpeechGrammar element) => Collections.contains(this, element); - - void forEach(void f(SpeechGrammar element)) => Collections.forEach(this, f); - - Collection map(f(SpeechGrammar element)) => Collections.map(this, [], f); - - Collection filter(bool f(SpeechGrammar element)) => - Collections.filter(this, [], f); - - bool every(bool f(SpeechGrammar element)) => Collections.every(this, f); - - bool some(bool f(SpeechGrammar element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -16220,9 +17033,25 @@ class SpeechGrammarList implements JavaScriptIndexingBehavior, List this[0]; + SpeechGrammar get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SpeechGrammar get last => this[length - 1]; + SpeechGrammar get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SpeechGrammar get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SpeechGrammar min([int compare(SpeechGrammar a, SpeechGrammar b)]) => _Collections.minInList(this, compare); + + SpeechGrammar max([int compare(SpeechGrammar a, SpeechGrammar b)]) => _Collections.maxInList(this, compare); SpeechGrammar removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -16540,13 +17369,61 @@ class SqlResultSetRowList implements JavaScriptIndexingBehavior, List nativ // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Map element) => Collections.contains(this, element); + + void forEach(void f(Map element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Map element)) => new MappedList(this, f); + + Iterable where(bool f(Map element)) => new WhereIterable(this, f); + + bool every(bool f(Map element)) => Collections.every(this, f); + + bool any(bool f(Map element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Map value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Map value)) { + return new SkipWhileIterable(this, test); + } + + Map firstMatching(bool test(Map value), { Map orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Map lastMatching(bool test(Map value), {Map orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Map singleMatching(bool test(Map value)) { + return Collections.singleMatching(this, test); + } + + Map elementAt(int index) { + return this[index]; + } + // From Collection: void add(Map value) { @@ -16557,29 +17434,10 @@ class SqlResultSetRowList implements JavaScriptIndexingBehavior, List nativ throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Map element) => Collections.contains(this, element); - - void forEach(void f(Map element)) => Collections.forEach(this, f); - - Collection map(f(Map element)) => Collections.map(this, [], f); - - Collection filter(bool f(Map element)) => - Collections.filter(this, [], f); - - bool every(bool f(Map element)) => Collections.every(this, f); - - bool some(bool f(Map element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -16601,9 +17459,25 @@ class SqlResultSetRowList implements JavaScriptIndexingBehavior, List nativ return Lists.lastIndexOf(this, element, start); } - Map get first => this[0]; + Map get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Map get last => this[length - 1]; + Map get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Map get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Map min([int compare(Map a, Map b)]) => _Collections.minInList(this, compare); + + Map max([int compare(Map a, Map b)]) => _Collections.maxInList(this, compare); Map removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -16669,7 +17543,7 @@ class SqlTransactionSync native "*SQLTransactionSync" { class Storage implements Map native "*Storage" { // TODO(nweiz): update this when maps support lazy iteration - bool containsValue(String value) => values.some((e) => e == value); + bool containsValue(String value) => values.any((e) => e == value); bool containsKey(String key) => $dom_getItem(key) != null; @@ -17345,13 +18219,61 @@ class TextTrackCueList implements List, JavaScriptIndexingBehavior // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrackCue)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(TextTrackCue element) => Collections.contains(this, element); + + void forEach(void f(TextTrackCue element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(TextTrackCue element)) => new MappedList(this, f); + + Iterable where(bool f(TextTrackCue element)) => new WhereIterable(this, f); + + bool every(bool f(TextTrackCue element)) => Collections.every(this, f); + + bool any(bool f(TextTrackCue element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(TextTrackCue value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(TextTrackCue value)) { + return new SkipWhileIterable(this, test); + } + + TextTrackCue firstMatching(bool test(TextTrackCue value), { TextTrackCue orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + TextTrackCue lastMatching(bool test(TextTrackCue value), {TextTrackCue orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + TextTrackCue singleMatching(bool test(TextTrackCue value)) { + return Collections.singleMatching(this, test); + } + + TextTrackCue elementAt(int index) { + return this[index]; + } + // From Collection: void add(TextTrackCue value) { @@ -17362,29 +18284,10 @@ class TextTrackCueList implements List, JavaScriptIndexingBehavior throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrackCue)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(TextTrackCue element) => Collections.contains(this, element); - - void forEach(void f(TextTrackCue element)) => Collections.forEach(this, f); - - Collection map(f(TextTrackCue element)) => Collections.map(this, [], f); - - Collection filter(bool f(TextTrackCue element)) => - Collections.filter(this, [], f); - - bool every(bool f(TextTrackCue element)) => Collections.every(this, f); - - bool some(bool f(TextTrackCue element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -17406,9 +18309,25 @@ class TextTrackCueList implements List, JavaScriptIndexingBehavior return Lists.lastIndexOf(this, element, start); } - TextTrackCue get first => this[0]; + TextTrackCue get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - TextTrackCue get last => this[length - 1]; + TextTrackCue get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + TextTrackCue get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + TextTrackCue min([int compare(TextTrackCue a, TextTrackCue b)]) => _Collections.minInList(this, compare); + + TextTrackCue max([int compare(TextTrackCue a, TextTrackCue b)]) => _Collections.maxInList(this, compare); TextTrackCue removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -17466,13 +18385,61 @@ class TextTrackList extends EventTarget implements JavaScriptIndexingBehavior, L // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrack)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(TextTrack element) => Collections.contains(this, element); + + void forEach(void f(TextTrack element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(TextTrack element)) => new MappedList(this, f); + + Iterable where(bool f(TextTrack element)) => new WhereIterable(this, f); + + bool every(bool f(TextTrack element)) => Collections.every(this, f); + + bool any(bool f(TextTrack element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(TextTrack value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(TextTrack value)) { + return new SkipWhileIterable(this, test); + } + + TextTrack firstMatching(bool test(TextTrack value), { TextTrack orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + TextTrack lastMatching(bool test(TextTrack value), {TextTrack orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + TextTrack singleMatching(bool test(TextTrack value)) { + return Collections.singleMatching(this, test); + } + + TextTrack elementAt(int index) { + return this[index]; + } + // From Collection: void add(TextTrack value) { @@ -17483,29 +18450,10 @@ class TextTrackList extends EventTarget implements JavaScriptIndexingBehavior, L throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrack)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(TextTrack element) => Collections.contains(this, element); - - void forEach(void f(TextTrack element)) => Collections.forEach(this, f); - - Collection map(f(TextTrack element)) => Collections.map(this, [], f); - - Collection filter(bool f(TextTrack element)) => - Collections.filter(this, [], f); - - bool every(bool f(TextTrack element)) => Collections.every(this, f); - - bool some(bool f(TextTrack element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -17527,9 +18475,25 @@ class TextTrackList extends EventTarget implements JavaScriptIndexingBehavior, L return Lists.lastIndexOf(this, element, start); } - TextTrack get first => this[0]; + TextTrack get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - TextTrack get last => this[length - 1]; + TextTrack get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + TextTrack get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + TextTrack min([int compare(TextTrack a, TextTrack b)]) => _Collections.minInList(this, compare); + + TextTrack max([int compare(TextTrack a, TextTrack b)]) => _Collections.maxInList(this, compare); TextTrack removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -17716,13 +18680,61 @@ class TouchList implements JavaScriptIndexingBehavior, List native "*Touc // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Touch)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Touch element) => Collections.contains(this, element); + + void forEach(void f(Touch element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Touch element)) => new MappedList(this, f); + + Iterable where(bool f(Touch element)) => new WhereIterable(this, f); + + bool every(bool f(Touch element)) => Collections.every(this, f); + + bool any(bool f(Touch element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Touch value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Touch value)) { + return new SkipWhileIterable(this, test); + } + + Touch firstMatching(bool test(Touch value), { Touch orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Touch lastMatching(bool test(Touch value), {Touch orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Touch singleMatching(bool test(Touch value)) { + return Collections.singleMatching(this, test); + } + + Touch elementAt(int index) { + return this[index]; + } + // From Collection: void add(Touch value) { @@ -17733,29 +18745,10 @@ class TouchList implements JavaScriptIndexingBehavior, List native "*Touc throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Touch)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Touch element) => Collections.contains(this, element); - - void forEach(void f(Touch element)) => Collections.forEach(this, f); - - Collection map(f(Touch element)) => Collections.map(this, [], f); - - Collection filter(bool f(Touch element)) => - Collections.filter(this, [], f); - - bool every(bool f(Touch element)) => Collections.every(this, f); - - bool some(bool f(Touch element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -17777,9 +18770,25 @@ class TouchList implements JavaScriptIndexingBehavior, List native "*Touc return Lists.lastIndexOf(this, element, start); } - Touch get first => this[0]; + Touch get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Touch get last => this[length - 1]; + Touch get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Touch get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Touch min([int compare(Touch a, Touch b)]) => _Collections.minInList(this, compare); + + Touch max([int compare(Touch a, Touch b)]) => _Collections.maxInList(this, compare); Touch removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -18026,13 +19035,61 @@ class Uint16Array extends ArrayBufferView implements JavaScriptIndexingBehavior, // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -18043,29 +19100,10 @@ class Uint16Array extends ArrayBufferView implements JavaScriptIndexingBehavior, throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -18087,9 +19125,25 @@ class Uint16Array extends ArrayBufferView implements JavaScriptIndexingBehavior, return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -18152,13 +19206,61 @@ class Uint32Array extends ArrayBufferView implements JavaScriptIndexingBehavior, // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -18169,29 +19271,10 @@ class Uint32Array extends ArrayBufferView implements JavaScriptIndexingBehavior, throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -18213,9 +19296,25 @@ class Uint32Array extends ArrayBufferView implements JavaScriptIndexingBehavior, return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -18278,13 +19377,61 @@ class Uint8Array extends ArrayBufferView implements JavaScriptIndexingBehavior, // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -18295,29 +19442,10 @@ class Uint8Array extends ArrayBufferView implements JavaScriptIndexingBehavior, throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -18339,9 +19467,25 @@ class Uint8Array extends ArrayBufferView implements JavaScriptIndexingBehavior, return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -20221,7 +21365,7 @@ class Window extends EventTarget implements WindowBase native "@*DOMWindow" { * registered under [name]. */ SendPortSync lookupPort(String name) { - var port = JSON.parse(document.documentElement.attributes['dart-port:$name']); + var port = json.parse(document.documentElement.attributes['dart-port:$name']); return _deserialize(port); } @@ -20232,7 +21376,7 @@ class Window extends EventTarget implements WindowBase native "@*DOMWindow" { */ void registerPort(String name, var port) { var serialized = _serialize(port); - document.documentElement.attributes['dart-port:$name'] = JSON.stringify(serialized); + document.documentElement.attributes['dart-port:$name'] = json.stringify(serialized); } /// @domName Window.console; @docsEditable true @@ -21150,13 +22294,61 @@ class _ClientRectList implements JavaScriptIndexingBehavior, List na // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ClientRect)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(ClientRect element) => Collections.contains(this, element); + + void forEach(void f(ClientRect element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(ClientRect element)) => new MappedList(this, f); + + Iterable where(bool f(ClientRect element)) => new WhereIterable(this, f); + + bool every(bool f(ClientRect element)) => Collections.every(this, f); + + bool any(bool f(ClientRect element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(ClientRect value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(ClientRect value)) { + return new SkipWhileIterable(this, test); + } + + ClientRect firstMatching(bool test(ClientRect value), { ClientRect orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + ClientRect lastMatching(bool test(ClientRect value), {ClientRect orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + ClientRect singleMatching(bool test(ClientRect value)) { + return Collections.singleMatching(this, test); + } + + ClientRect elementAt(int index) { + return this[index]; + } + // From Collection: void add(ClientRect value) { @@ -21167,29 +22359,10 @@ class _ClientRectList implements JavaScriptIndexingBehavior, List na throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ClientRect)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(ClientRect element) => Collections.contains(this, element); - - void forEach(void f(ClientRect element)) => Collections.forEach(this, f); - - Collection map(f(ClientRect element)) => Collections.map(this, [], f); - - Collection filter(bool f(ClientRect element)) => - Collections.filter(this, [], f); - - bool every(bool f(ClientRect element)) => Collections.every(this, f); - - bool some(bool f(ClientRect element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21211,9 +22384,25 @@ class _ClientRectList implements JavaScriptIndexingBehavior, List na return Lists.lastIndexOf(this, element, start); } - ClientRect get first => this[0]; + ClientRect get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - ClientRect get last => this[length - 1]; + ClientRect get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + ClientRect get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + ClientRect min([int compare(ClientRect a, ClientRect b)]) => _Collections.minInList(this, compare); + + ClientRect max([int compare(ClientRect a, ClientRect b)]) => _Collections.maxInList(this, compare); ClientRect removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21264,13 +22453,61 @@ class _CssRuleList implements JavaScriptIndexingBehavior, List native " // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssRule)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(CssRule element) => Collections.contains(this, element); + + void forEach(void f(CssRule element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(CssRule element)) => new MappedList(this, f); + + Iterable where(bool f(CssRule element)) => new WhereIterable(this, f); + + bool every(bool f(CssRule element)) => Collections.every(this, f); + + bool any(bool f(CssRule element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(CssRule value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(CssRule value)) { + return new SkipWhileIterable(this, test); + } + + CssRule firstMatching(bool test(CssRule value), { CssRule orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + CssRule lastMatching(bool test(CssRule value), {CssRule orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + CssRule singleMatching(bool test(CssRule value)) { + return Collections.singleMatching(this, test); + } + + CssRule elementAt(int index) { + return this[index]; + } + // From Collection: void add(CssRule value) { @@ -21281,29 +22518,10 @@ class _CssRuleList implements JavaScriptIndexingBehavior, List native " throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssRule)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(CssRule element) => Collections.contains(this, element); - - void forEach(void f(CssRule element)) => Collections.forEach(this, f); - - Collection map(f(CssRule element)) => Collections.map(this, [], f); - - Collection filter(bool f(CssRule element)) => - Collections.filter(this, [], f); - - bool every(bool f(CssRule element)) => Collections.every(this, f); - - bool some(bool f(CssRule element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21325,9 +22543,25 @@ class _CssRuleList implements JavaScriptIndexingBehavior, List native " return Lists.lastIndexOf(this, element, start); } - CssRule get first => this[0]; + CssRule get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - CssRule get last => this[length - 1]; + CssRule get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + CssRule get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + CssRule min([int compare(CssRule a, CssRule b)]) => _Collections.minInList(this, compare); + + CssRule max([int compare(CssRule a, CssRule b)]) => _Collections.maxInList(this, compare); CssRule removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21378,13 +22612,61 @@ class _CssValueList extends CssValue implements List, JavaScriptIndexi // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssValue)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(CssValue element) => Collections.contains(this, element); + + void forEach(void f(CssValue element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(CssValue element)) => new MappedList(this, f); + + Iterable where(bool f(CssValue element)) => new WhereIterable(this, f); + + bool every(bool f(CssValue element)) => Collections.every(this, f); + + bool any(bool f(CssValue element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(CssValue value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(CssValue value)) { + return new SkipWhileIterable(this, test); + } + + CssValue firstMatching(bool test(CssValue value), { CssValue orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + CssValue lastMatching(bool test(CssValue value), {CssValue orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + CssValue singleMatching(bool test(CssValue value)) { + return Collections.singleMatching(this, test); + } + + CssValue elementAt(int index) { + return this[index]; + } + // From Collection: void add(CssValue value) { @@ -21395,29 +22677,10 @@ class _CssValueList extends CssValue implements List, JavaScriptIndexi throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssValue)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(CssValue element) => Collections.contains(this, element); - - void forEach(void f(CssValue element)) => Collections.forEach(this, f); - - Collection map(f(CssValue element)) => Collections.map(this, [], f); - - Collection filter(bool f(CssValue element)) => - Collections.filter(this, [], f); - - bool every(bool f(CssValue element)) => Collections.every(this, f); - - bool some(bool f(CssValue element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21439,9 +22702,25 @@ class _CssValueList extends CssValue implements List, JavaScriptIndexi return Lists.lastIndexOf(this, element, start); } - CssValue get first => this[0]; + CssValue get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - CssValue get last => this[length - 1]; + CssValue get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + CssValue get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + CssValue min([int compare(CssValue a, CssValue b)]) => _Collections.minInList(this, compare); + + CssValue max([int compare(CssValue a, CssValue b)]) => _Collections.maxInList(this, compare); CssValue removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21492,13 +22771,61 @@ class _EntryArray implements JavaScriptIndexingBehavior, List native "*En // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Entry)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Entry element) => Collections.contains(this, element); + + void forEach(void f(Entry element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Entry element)) => new MappedList(this, f); + + Iterable where(bool f(Entry element)) => new WhereIterable(this, f); + + bool every(bool f(Entry element)) => Collections.every(this, f); + + bool any(bool f(Entry element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Entry value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Entry value)) { + return new SkipWhileIterable(this, test); + } + + Entry firstMatching(bool test(Entry value), { Entry orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Entry lastMatching(bool test(Entry value), {Entry orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Entry singleMatching(bool test(Entry value)) { + return Collections.singleMatching(this, test); + } + + Entry elementAt(int index) { + return this[index]; + } + // From Collection: void add(Entry value) { @@ -21509,29 +22836,10 @@ class _EntryArray implements JavaScriptIndexingBehavior, List native "*En throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Entry)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Entry element) => Collections.contains(this, element); - - void forEach(void f(Entry element)) => Collections.forEach(this, f); - - Collection map(f(Entry element)) => Collections.map(this, [], f); - - Collection filter(bool f(Entry element)) => - Collections.filter(this, [], f); - - bool every(bool f(Entry element)) => Collections.every(this, f); - - bool some(bool f(Entry element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21553,9 +22861,25 @@ class _EntryArray implements JavaScriptIndexingBehavior, List native "*En return Lists.lastIndexOf(this, element, start); } - Entry get first => this[0]; + Entry get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Entry get last => this[length - 1]; + Entry get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Entry get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Entry min([int compare(Entry a, Entry b)]) => _Collections.minInList(this, compare); + + Entry max([int compare(Entry a, Entry b)]) => _Collections.maxInList(this, compare); Entry removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21606,13 +22930,61 @@ class _EntryArraySync implements JavaScriptIndexingBehavior, List nat // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, EntrySync)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(EntrySync element) => Collections.contains(this, element); + + void forEach(void f(EntrySync element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(EntrySync element)) => new MappedList(this, f); + + Iterable where(bool f(EntrySync element)) => new WhereIterable(this, f); + + bool every(bool f(EntrySync element)) => Collections.every(this, f); + + bool any(bool f(EntrySync element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(EntrySync value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(EntrySync value)) { + return new SkipWhileIterable(this, test); + } + + EntrySync firstMatching(bool test(EntrySync value), { EntrySync orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + EntrySync lastMatching(bool test(EntrySync value), {EntrySync orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + EntrySync singleMatching(bool test(EntrySync value)) { + return Collections.singleMatching(this, test); + } + + EntrySync elementAt(int index) { + return this[index]; + } + // From Collection: void add(EntrySync value) { @@ -21623,29 +22995,10 @@ class _EntryArraySync implements JavaScriptIndexingBehavior, List nat throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, EntrySync)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(EntrySync element) => Collections.contains(this, element); - - void forEach(void f(EntrySync element)) => Collections.forEach(this, f); - - Collection map(f(EntrySync element)) => Collections.map(this, [], f); - - Collection filter(bool f(EntrySync element)) => - Collections.filter(this, [], f); - - bool every(bool f(EntrySync element)) => Collections.every(this, f); - - bool some(bool f(EntrySync element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21667,9 +23020,25 @@ class _EntryArraySync implements JavaScriptIndexingBehavior, List nat return Lists.lastIndexOf(this, element, start); } - EntrySync get first => this[0]; + EntrySync get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - EntrySync get last => this[length - 1]; + EntrySync get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + EntrySync get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + EntrySync min([int compare(EntrySync a, EntrySync b)]) => _Collections.minInList(this, compare); + + EntrySync max([int compare(EntrySync a, EntrySync b)]) => _Collections.maxInList(this, compare); EntrySync removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21720,13 +23089,61 @@ class _GamepadList implements JavaScriptIndexingBehavior, List native " // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Gamepad)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Gamepad element) => Collections.contains(this, element); + + void forEach(void f(Gamepad element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Gamepad element)) => new MappedList(this, f); + + Iterable where(bool f(Gamepad element)) => new WhereIterable(this, f); + + bool every(bool f(Gamepad element)) => Collections.every(this, f); + + bool any(bool f(Gamepad element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Gamepad value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Gamepad value)) { + return new SkipWhileIterable(this, test); + } + + Gamepad firstMatching(bool test(Gamepad value), { Gamepad orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Gamepad lastMatching(bool test(Gamepad value), {Gamepad orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Gamepad singleMatching(bool test(Gamepad value)) { + return Collections.singleMatching(this, test); + } + + Gamepad elementAt(int index) { + return this[index]; + } + // From Collection: void add(Gamepad value) { @@ -21737,29 +23154,10 @@ class _GamepadList implements JavaScriptIndexingBehavior, List native " throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Gamepad)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Gamepad element) => Collections.contains(this, element); - - void forEach(void f(Gamepad element)) => Collections.forEach(this, f); - - Collection map(f(Gamepad element)) => Collections.map(this, [], f); - - Collection filter(bool f(Gamepad element)) => - Collections.filter(this, [], f); - - bool every(bool f(Gamepad element)) => Collections.every(this, f); - - bool some(bool f(Gamepad element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21781,9 +23179,25 @@ class _GamepadList implements JavaScriptIndexingBehavior, List native " return Lists.lastIndexOf(this, element, start); } - Gamepad get first => this[0]; + Gamepad get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Gamepad get last => this[length - 1]; + Gamepad get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Gamepad get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Gamepad min([int compare(Gamepad a, Gamepad b)]) => _Collections.minInList(this, compare); + + Gamepad max([int compare(Gamepad a, Gamepad b)]) => _Collections.maxInList(this, compare); Gamepad removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21834,13 +23248,61 @@ class _MediaStreamList implements JavaScriptIndexingBehavior, List // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, MediaStream)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(MediaStream element) => Collections.contains(this, element); + + void forEach(void f(MediaStream element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(MediaStream element)) => new MappedList(this, f); + + Iterable where(bool f(MediaStream element)) => new WhereIterable(this, f); + + bool every(bool f(MediaStream element)) => Collections.every(this, f); + + bool any(bool f(MediaStream element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(MediaStream value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(MediaStream value)) { + return new SkipWhileIterable(this, test); + } + + MediaStream firstMatching(bool test(MediaStream value), { MediaStream orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + MediaStream lastMatching(bool test(MediaStream value), {MediaStream orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + MediaStream singleMatching(bool test(MediaStream value)) { + return Collections.singleMatching(this, test); + } + + MediaStream elementAt(int index) { + return this[index]; + } + // From Collection: void add(MediaStream value) { @@ -21851,29 +23313,10 @@ class _MediaStreamList implements JavaScriptIndexingBehavior, List throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, MediaStream)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(MediaStream element) => Collections.contains(this, element); - - void forEach(void f(MediaStream element)) => Collections.forEach(this, f); - - Collection map(f(MediaStream element)) => Collections.map(this, [], f); - - Collection filter(bool f(MediaStream element)) => - Collections.filter(this, [], f); - - bool every(bool f(MediaStream element)) => Collections.every(this, f); - - bool some(bool f(MediaStream element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21895,9 +23338,25 @@ class _MediaStreamList implements JavaScriptIndexingBehavior, List return Lists.lastIndexOf(this, element, start); } - MediaStream get first => this[0]; + MediaStream get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - MediaStream get last => this[length - 1]; + MediaStream get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + MediaStream get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + MediaStream min([int compare(MediaStream a, MediaStream b)]) => _Collections.minInList(this, compare); + + MediaStream max([int compare(MediaStream a, MediaStream b)]) => _Collections.maxInList(this, compare); MediaStream removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21948,13 +23407,61 @@ class _SpeechInputResultList implements JavaScriptIndexingBehavior, List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechInputResult)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SpeechInputResult element) => Collections.contains(this, element); + + void forEach(void f(SpeechInputResult element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SpeechInputResult element)) => new MappedList(this, f); + + Iterable where(bool f(SpeechInputResult element)) => new WhereIterable(this, f); + + bool every(bool f(SpeechInputResult element)) => Collections.every(this, f); + + bool any(bool f(SpeechInputResult element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SpeechInputResult value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SpeechInputResult value)) { + return new SkipWhileIterable(this, test); + } + + SpeechInputResult firstMatching(bool test(SpeechInputResult value), { SpeechInputResult orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SpeechInputResult lastMatching(bool test(SpeechInputResult value), {SpeechInputResult orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SpeechInputResult singleMatching(bool test(SpeechInputResult value)) { + return Collections.singleMatching(this, test); + } + + SpeechInputResult elementAt(int index) { + return this[index]; + } + // From Collection: void add(SpeechInputResult value) { @@ -21965,29 +23472,10 @@ class _SpeechInputResultList implements JavaScriptIndexingBehavior, List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechInputResult)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SpeechInputResult element) => Collections.contains(this, element); - - void forEach(void f(SpeechInputResult element)) => Collections.forEach(this, f); - - Collection map(f(SpeechInputResult element)) => Collections.map(this, [], f); - - Collection filter(bool f(SpeechInputResult element)) => - Collections.filter(this, [], f); - - bool every(bool f(SpeechInputResult element)) => Collections.every(this, f); - - bool some(bool f(SpeechInputResult element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -22009,9 +23497,25 @@ class _SpeechInputResultList implements JavaScriptIndexingBehavior, List this[0]; + SpeechInputResult get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SpeechInputResult get last => this[length - 1]; + SpeechInputResult get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SpeechInputResult get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SpeechInputResult min([int compare(SpeechInputResult a, SpeechInputResult b)]) => _Collections.minInList(this, compare); + + SpeechInputResult max([int compare(SpeechInputResult a, SpeechInputResult b)]) => _Collections.maxInList(this, compare); SpeechInputResult removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -22062,13 +23566,61 @@ class _SpeechRecognitionResultList implements JavaScriptIndexingBehavior, List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechRecognitionResult)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SpeechRecognitionResult element) => Collections.contains(this, element); + + void forEach(void f(SpeechRecognitionResult element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SpeechRecognitionResult element)) => new MappedList(this, f); + + Iterable where(bool f(SpeechRecognitionResult element)) => new WhereIterable(this, f); + + bool every(bool f(SpeechRecognitionResult element)) => Collections.every(this, f); + + bool any(bool f(SpeechRecognitionResult element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SpeechRecognitionResult value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SpeechRecognitionResult value)) { + return new SkipWhileIterable(this, test); + } + + SpeechRecognitionResult firstMatching(bool test(SpeechRecognitionResult value), { SpeechRecognitionResult orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SpeechRecognitionResult lastMatching(bool test(SpeechRecognitionResult value), {SpeechRecognitionResult orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SpeechRecognitionResult singleMatching(bool test(SpeechRecognitionResult value)) { + return Collections.singleMatching(this, test); + } + + SpeechRecognitionResult elementAt(int index) { + return this[index]; + } + // From Collection: void add(SpeechRecognitionResult value) { @@ -22079,29 +23631,10 @@ class _SpeechRecognitionResultList implements JavaScriptIndexingBehavior, List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechRecognitionResult)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SpeechRecognitionResult element) => Collections.contains(this, element); - - void forEach(void f(SpeechRecognitionResult element)) => Collections.forEach(this, f); - - Collection map(f(SpeechRecognitionResult element)) => Collections.map(this, [], f); - - Collection filter(bool f(SpeechRecognitionResult element)) => - Collections.filter(this, [], f); - - bool every(bool f(SpeechRecognitionResult element)) => Collections.every(this, f); - - bool some(bool f(SpeechRecognitionResult element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -22123,9 +23656,25 @@ class _SpeechRecognitionResultList implements JavaScriptIndexingBehavior, List this[0]; + SpeechRecognitionResult get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SpeechRecognitionResult get last => this[length - 1]; + SpeechRecognitionResult get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SpeechRecognitionResult get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SpeechRecognitionResult min([int compare(SpeechRecognitionResult a, SpeechRecognitionResult b)]) => _Collections.minInList(this, compare); + + SpeechRecognitionResult max([int compare(SpeechRecognitionResult a, SpeechRecognitionResult b)]) => _Collections.maxInList(this, compare); SpeechRecognitionResult removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -22176,13 +23725,61 @@ class _StyleSheetList implements JavaScriptIndexingBehavior, List na // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, StyleSheet)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(StyleSheet element) => Collections.contains(this, element); + + void forEach(void f(StyleSheet element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(StyleSheet element)) => new MappedList(this, f); + + Iterable where(bool f(StyleSheet element)) => new WhereIterable(this, f); + + bool every(bool f(StyleSheet element)) => Collections.every(this, f); + + bool any(bool f(StyleSheet element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(StyleSheet value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(StyleSheet value)) { + return new SkipWhileIterable(this, test); + } + + StyleSheet firstMatching(bool test(StyleSheet value), { StyleSheet orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + StyleSheet lastMatching(bool test(StyleSheet value), {StyleSheet orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + StyleSheet singleMatching(bool test(StyleSheet value)) { + return Collections.singleMatching(this, test); + } + + StyleSheet elementAt(int index) { + return this[index]; + } + // From Collection: void add(StyleSheet value) { @@ -22193,29 +23790,10 @@ class _StyleSheetList implements JavaScriptIndexingBehavior, List na throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, StyleSheet)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(StyleSheet element) => Collections.contains(this, element); - - void forEach(void f(StyleSheet element)) => Collections.forEach(this, f); - - Collection map(f(StyleSheet element)) => Collections.map(this, [], f); - - Collection filter(bool f(StyleSheet element)) => - Collections.filter(this, [], f); - - bool every(bool f(StyleSheet element)) => Collections.every(this, f); - - bool some(bool f(StyleSheet element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -22237,9 +23815,25 @@ class _StyleSheetList implements JavaScriptIndexingBehavior, List na return Lists.lastIndexOf(this, element, start); } - StyleSheet get first => this[0]; + StyleSheet get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - StyleSheet get last => this[length - 1]; + StyleSheet get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + StyleSheet get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + StyleSheet min([int compare(StyleSheet a, StyleSheet b)]) => _Collections.minInList(this, compare); + + StyleSheet max([int compare(StyleSheet a, StyleSheet b)]) => _Collections.maxInList(this, compare); StyleSheet removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -22431,7 +24025,7 @@ class _DataAttributeMap implements Map { // interface Map // TODO: Use lazy iterator when it is available on Map. - bool containsValue(String value) => values.some((v) => v == value); + bool containsValue(String value) => values.any((v) => v == value); bool containsKey(String key) => $dom_attributes.containsKey(_attr(key)); @@ -22654,7 +24248,7 @@ abstract class CssClassSet implements Set { bool get frozen => false; // interface Iterable - BEGIN - Iterator iterator() => readClasses().iterator(); + Iterator get iterator => readClasses().iterator; // interface Iterable - END // interface Collection - BEGIN @@ -22662,13 +24256,15 @@ abstract class CssClassSet implements Set { readClasses().forEach(f); } - Collection map(f(String element)) => readClasses().map(f); + String join([String separator]) => readClasses().join(separator); - Collection filter(bool f(String element)) => readClasses().filter(f); + Iterable mappedBy(f(String element)) => readClasses().mappedBy(f); + + Iterable where(bool f(String element)) => readClasses().where(f); bool every(bool f(String element)) => readClasses().every(f); - bool some(bool f(String element)) => readClasses().some(f); + bool any(bool f(String element)) => readClasses().any(f); bool get isEmpty => readClasses().isEmpty; @@ -22696,13 +24292,13 @@ abstract class CssClassSet implements Set { return result; } - void addAll(Collection collection) { + void addAll(Iterable iterable) { // TODO - see comment above about validation - _modify((s) => s.addAll(collection)); + _modify((s) => s.addAll(iterable)); } - void removeAll(Collection collection) { - _modify((s) => s.removeAll(collection)); + void removeAll(Iterable iterable) { + _modify((s) => s.removeAll(iterable)); } bool isSubsetOf(Collection collection) => @@ -22941,7 +24537,7 @@ class KeyboardEventController { /** Determine if caps lock is one of the currently depressed keys. */ bool get _capsLockOn => - _keyDownList.some((var element) => element.keyCode == KeyCode.CAPS_LOCK); + _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); /** * Given the previously recorded keydown key codes, see if we can determine @@ -23170,7 +24766,7 @@ class KeyboardEventController { // keyCode/which for non printable keys. e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]; } - e._shadowAltKey = _keyDownList.some((var element) => element.altKey); + e._shadowAltKey = _keyDownList.any((var element) => element.altKey); _dispatch(e); } @@ -23184,7 +24780,8 @@ class KeyboardEventController { } } if (toRemove != null) { - _keyDownList = _keyDownList.filter((element) => element != toRemove); + _keyDownList = + _keyDownList.where((element) => element != toRemove).toList(); } else if (_keyDownList.length > 0) { // This happens when we've reached some international keyboard case we // haven't accounted for or we haven't correctly eliminated all browser @@ -24140,7 +25737,7 @@ class _RemoteSendPortSync implements SendPortSync { var source = '$target-result'; var result = null; var listener = (Event e) { - result = JSON.parse(_getPortSyncEventData(e)); + result = json.parse(_getPortSyncEventData(e)); }; window.on[source].add(listener); _dispatchEvent(target, [source, message]); @@ -24212,7 +25809,7 @@ class ReceivePortSync { _callback = callback; if (_listener == null) { _listener = (Event e) { - var data = JSON.parse(_getPortSyncEventData(e)); + var data = json.parse(_getPortSyncEventData(e)); var replyTo = data[0]; var message = _deserialize(data[1]); var result = _callback(message); @@ -24243,7 +25840,7 @@ class ReceivePortSync { get _isolateId => ReceivePortSync._isolateId; void _dispatchEvent(String receiver, var message) { - var event = new CustomEvent(receiver, false, false, JSON.stringify(message)); + var event = new CustomEvent(receiver, false, false, json.stringify(message)); window.$dom_dispatchEvent(event); } @@ -24538,15 +26135,15 @@ abstract class _Serializer extends _MessageTraverser { int id = _nextFreeRefId++; _visited[map] = id; - var keys = _serializeList(map.keys); - var values = _serializeList(map.values); + var keys = _serializeList(map.keys.toList()); + var values = _serializeList(map.values.toList()); // TODO(floitsch): we are losing the generic type. return ['map', id, keys, values]; } _serializeList(List list) { int len = list.length; - var result = new List(len); + var result = new List.fixedLength(len); for (int i = 0; i < len; i++) { result[i] = _dispatch(list[i]); } @@ -25274,31 +26871,53 @@ class Testing { // Iterator for arrays with fixed size. -class FixedSizeListIterator extends _VariableSizeListIterator { +class FixedSizeListIterator implements Iterator { + final List _array; + final int _length; // Cache array length for faster access. + int _position; + T _current; + FixedSizeListIterator(List array) - : super(array), + : _array = array, + _position = -1, _length = array.length; - bool get hasNext => _length > _pos; + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; + } + _current = null; + _position = _length; + return false; + } - final int _length; // Cache array length for faster access. + T get current => _current; } // Iterator for arrays with variable size. class _VariableSizeListIterator implements Iterator { + final List _array; + int _position; + T _current; + _VariableSizeListIterator(List array) : _array = array, - _pos = 0; + _position = -1; - bool get hasNext => _array.length > _pos; - - T next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _array.length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; } - return _array[_pos++]; + _current = null; + _position = _array.length; + return false; } - final List _array; - int _pos; + T get current => _current; } diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart index b515403b7b5..cb6dbe2ea39 100644 --- a/sdk/lib/html/dartium/html_dartium.dart +++ b/sdk/lib/html/dartium/html_dartium.dart @@ -1,10 +1,11 @@ library html; +import 'dart:async'; import 'dart:collection'; import 'dart:html_common'; import 'dart:indexed_db'; import 'dart:isolate'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:nativewrappers'; import 'dart:svg' as svg; import 'dart:web_audio' as web_audio; @@ -54,7 +55,7 @@ var _callPortLastResult = null; _callPortSync(num id, var message) { if (!_callPortInitialized) { window.on['js-result'].add((event) { - _callPortLastResult = JSON.parse(_getPortSyncEventData(event)); + _callPortLastResult = json.parse(_getPortSyncEventData(event)); }, false); _callPortInitialized = true; } @@ -7063,7 +7064,7 @@ class Document extends Node final mutableMatches = $dom_getElementsByName( selectors.substring(7,selectors.length - 2)); int len = mutableMatches.length; - final copyOfMatches = new List(len); + final copyOfMatches = new List.fixedLength(len); for (int i = 0; i < len; ++i) { copyOfMatches[i] = mutableMatches[i]; } @@ -7071,7 +7072,7 @@ class Document extends Node } else if (new RegExp("^[*a-zA-Z0-9]+\$").hasMatch(selectors)) { final mutableMatches = $dom_getElementsByTagName(selectors); int len = mutableMatches.length; - final copyOfMatches = new List(len); + final copyOfMatches = new List.fixedLength(len); for (int i = 0; i < len; ++i) { copyOfMatches[i] = mutableMatches[i]; } @@ -7598,13 +7599,61 @@ class DomMimeTypeArray extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomMimeType)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(DomMimeType element) => Collections.contains(this, element); + + void forEach(void f(DomMimeType element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(DomMimeType element)) => new MappedList(this, f); + + Iterable where(bool f(DomMimeType element)) => new WhereIterable(this, f); + + bool every(bool f(DomMimeType element)) => Collections.every(this, f); + + bool any(bool f(DomMimeType element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(DomMimeType value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(DomMimeType value)) { + return new SkipWhileIterable(this, test); + } + + DomMimeType firstMatching(bool test(DomMimeType value), { DomMimeType orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + DomMimeType lastMatching(bool test(DomMimeType value), {DomMimeType orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + DomMimeType singleMatching(bool test(DomMimeType value)) { + return Collections.singleMatching(this, test); + } + + DomMimeType elementAt(int index) { + return this[index]; + } + // From Collection: void add(DomMimeType value) { @@ -7615,29 +7664,10 @@ class DomMimeTypeArray extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomMimeType)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(DomMimeType element) => Collections.contains(this, element); - - void forEach(void f(DomMimeType element)) => Collections.forEach(this, f); - - Collection map(f(DomMimeType element)) => Collections.map(this, [], f); - - Collection filter(bool f(DomMimeType element)) => - Collections.filter(this, [], f); - - bool every(bool f(DomMimeType element)) => Collections.every(this, f); - - bool some(bool f(DomMimeType element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -7659,9 +7689,25 @@ class DomMimeTypeArray extends NativeFieldWrapperClass1 implements List this[0]; + DomMimeType get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - DomMimeType get last => this[length - 1]; + DomMimeType get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + DomMimeType get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + DomMimeType min([int compare(DomMimeType a, DomMimeType b)]) => _Collections.minInList(this, compare); + + DomMimeType max([int compare(DomMimeType a, DomMimeType b)]) => _Collections.maxInList(this, compare); DomMimeType removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -7778,13 +7824,61 @@ class DomPluginArray extends NativeFieldWrapperClass1 implements List // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomPlugin)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(DomPlugin element) => Collections.contains(this, element); + + void forEach(void f(DomPlugin element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(DomPlugin element)) => new MappedList(this, f); + + Iterable where(bool f(DomPlugin element)) => new WhereIterable(this, f); + + bool every(bool f(DomPlugin element)) => Collections.every(this, f); + + bool any(bool f(DomPlugin element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(DomPlugin value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(DomPlugin value)) { + return new SkipWhileIterable(this, test); + } + + DomPlugin firstMatching(bool test(DomPlugin value), { DomPlugin orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + DomPlugin lastMatching(bool test(DomPlugin value), {DomPlugin orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + DomPlugin singleMatching(bool test(DomPlugin value)) { + return Collections.singleMatching(this, test); + } + + DomPlugin elementAt(int index) { + return this[index]; + } + // From Collection: void add(DomPlugin value) { @@ -7795,29 +7889,10 @@ class DomPluginArray extends NativeFieldWrapperClass1 implements List throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, DomPlugin)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(DomPlugin element) => Collections.contains(this, element); - - void forEach(void f(DomPlugin element)) => Collections.forEach(this, f); - - Collection map(f(DomPlugin element)) => Collections.map(this, [], f); - - Collection filter(bool f(DomPlugin element)) => - Collections.filter(this, [], f); - - bool every(bool f(DomPlugin element)) => Collections.every(this, f); - - bool some(bool f(DomPlugin element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -7839,9 +7914,25 @@ class DomPluginArray extends NativeFieldWrapperClass1 implements List return Lists.lastIndexOf(this, element, start); } - DomPlugin get first => this[0]; + DomPlugin get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - DomPlugin get last => this[length - 1]; + DomPlugin get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + DomPlugin get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + DomPlugin min([int compare(DomPlugin a, DomPlugin b)]) => _Collections.minInList(this, compare); + + DomPlugin max([int compare(DomPlugin a, DomPlugin b)]) => _Collections.maxInList(this, compare); DomPlugin removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -8042,13 +8133,61 @@ class DomStringList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { + return Collections.reduce(this, initialValue, combine); + } + + // contains() defined by IDL. + + void forEach(void f(String element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(String element)) => new MappedList(this, f); + + Iterable where(bool f(String element)) => new WhereIterable(this, f); + + bool every(bool f(String element)) => Collections.every(this, f); + + bool any(bool f(String element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(String value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(String value)) { + return new SkipWhileIterable(this, test); + } + + String firstMatching(bool test(String value), { String orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + String lastMatching(bool test(String value), {String orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + String singleMatching(bool test(String value)) { + return Collections.singleMatching(this, test); + } + + String elementAt(int index) { + return this[index]; + } + // From Collection: void add(String value) { @@ -8059,29 +8198,10 @@ class DomStringList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { - return Collections.reduce(this, initialValue, combine); - } - - // contains() defined by IDL. - - void forEach(void f(String element)) => Collections.forEach(this, f); - - Collection map(f(String element)) => Collections.map(this, [], f); - - Collection filter(bool f(String element)) => - Collections.filter(this, [], f); - - bool every(bool f(String element)) => Collections.every(this, f); - - bool some(bool f(String element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -8103,9 +8223,25 @@ class DomStringList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - String get first => this[0]; + String get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - String get last => this[length - 1]; + String get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + String get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + String min([int compare(String a, String b)]) => _Collections.minInList(this, compare); + + String max([int compare(String a, String b)]) => _Collections.maxInList(this, compare); String removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -8212,14 +8348,22 @@ class _ChildrenElementList implements List { : _childElements = element.$dom_children, _element = element; - List _toList() { - final output = new List(_childElements.length); + List toList() { + final output = new List.fixedLength(_childElements.length); for (int i = 0, len = _childElements.length; i < len; i++) { output[i] = _childElements[i]; } return output; } + Set toSet() { + final output = new Set(_childElements.length); + for (int i = 0, len = _childElements.length; i < len; i++) { + output.add(_childElements[i]); + } + return output; + } + bool contains(Element element) => _childElements.contains(element); void forEach(void f(Element element)) { @@ -8228,46 +8372,71 @@ class _ChildrenElementList implements List { } } - List filter(bool f(Element element)) { - final output = []; - forEach((Element element) { - if (f(element)) { - output.add(element); - } - }); - return new _FrozenElementList._wrap(output); - } - bool every(bool f(Element element)) { for (Element element in this) { if (!f(element)) { return false; } - }; + } return true; } - bool some(bool f(Element element)) { + bool any(bool f(Element element)) { for (Element element in this) { if (f(element)) { return true; } - }; + } return false; } - Collection map(f(Element element)) { - final out = []; - for (Element el in this) { - out.add(f(el)); - } - return out; + String join([String separator]) { + return Collections.joinList(this, separator); } + List mappedBy(f(Element element)) { + return new MappedList(this, f); + } + + Iterable where(bool f(Element element)) + => new WhereIterable(this, f); + bool get isEmpty { return _element.$dom_firstElementChild == null; } + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(Element value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(Element value)) { + return new SkipWhileIterable(this, test); + } + + Element firstMatching(bool test(Element value), {Element orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Element singleMatching(bool test(Element value)) { + return Collections.singleMatching(this, test); + } + + Element elementAt(int index) { + return this[index]; + } + int get length { return _childElements.length; } @@ -8292,10 +8461,10 @@ class _ChildrenElementList implements List { Element addLast(Element value) => add(value); - Iterator iterator() => _toList().iterator(); + Iterator get iterator => toList().iterator; - void addAll(Collection collection) { - for (Element element in collection) { + void addAll(Iterable iterable) { + for (Element element in iterable) { _element.$dom_appendChild(element); } } @@ -8356,12 +8525,29 @@ class _ChildrenElementList implements List { } Element get first { - return _element.$dom_firstElementChild; + Element result = _element.$dom_firstElementChild; + if (result == null) throw new StateError("No elements"); + return result; } Element get last { - return _element.$dom_lastElementChild; + Element result = _element.$dom_lastElementChild; + if (result == null) throw new StateError("No elements"); + return result; + } + + Element get single { + if (length > 1) throw new StateError("More than one element"); + return first; + } + + Element min([int compare(Element a, Element b)]) { + return _Collections.minInList(this, compare); + } + + Element max([int compare(Element a, Element b)]) { + return _Collections.maxInList(this, compare); } } @@ -8387,22 +8573,17 @@ class _FrozenElementList implements List { } } - Collection map(f(Element element)) { - final out = []; - for (Element el in this) { - out.add(f(el)); - } - return out; + String join([String separator]) { + return Collections.joinList(this, separator); } - List filter(bool f(Element element)) { - final out = []; - for (Element el in this) { - if (f(el)) out.add(el); - } - return out; + List mappedBy(f(Element element)) { + return new MappedList(this, f); } + Iterable where(bool f(Element element)) + => new WhereIterable(this, f); + bool every(bool f(Element element)) { for(Element element in this) { if (!f(element)) { @@ -8412,7 +8593,7 @@ class _FrozenElementList implements List { return true; } - bool some(bool f(Element element)) { + bool any(bool f(Element element)) { for(Element element in this) { if (f(element)) { return true; @@ -8421,6 +8602,38 @@ class _FrozenElementList implements List { return false; } + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(T value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(T value)) { + return new SkipWhileIterable(this, test); + } + + Element firstMatching(bool test(Element value), {Element orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Element singleMatching(bool test(Element value)) { + return Collections.singleMatching(this, test); + } + + Element elementAt(int index) { + return this[index]; + } + bool get isEmpty => _nodeList.isEmpty; int get length => _nodeList.length; @@ -8443,9 +8656,9 @@ class _FrozenElementList implements List { throw new UnsupportedError(''); } - Iterator iterator() => new _FrozenElementListIterator(this); + Iterator get iterator => new _FrozenElementListIterator(this); - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError(''); } @@ -8494,6 +8707,16 @@ class _FrozenElementList implements List { Element get first => _nodeList.first; Element get last => _nodeList.last; + + Element get single => _nodeList.single; + + Element min([int compare(Element a, Element b)]) { + return _Collections.minInList(this, compare); + } + + Element max([int compare(Element a, Element b)]) { + return _Collections.maxInList(this, compare); + } } class _FrozenElementListIterator implements Iterator { @@ -8503,21 +8726,28 @@ class _FrozenElementListIterator implements Iterator { _FrozenElementListIterator(this._list); /** - * Gets the next element in the iteration. Throws a - * [StateError("No more elements")] if no element is left. + * Moves to the next element. Returns true if the iterator is positioned + * at an element. Returns false if it is positioned after the last element. */ - Element next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextIndex = _index + 1; + if (nextIndex < _list.length) { + _current = _list[nextIndex]; + _index = nextIndex; + return true; } - - return _list[_index++]; + _index = _list.length; + _current = null; + return false; } /** - * Returns whether the [Iterator] has elements left. + * Returns the element the [Iterator] is positioned at. + * + * Return [:null:] if the iterator is positioned before the first, or + * after the last element. */ - bool get hasNext => _index < _list.length; + E get current => _current; } class _ElementCssClassSet extends CssClassSet { @@ -8541,7 +8771,7 @@ class _ElementCssClassSet extends CssClassSet { void writeClasses(Set s) { List list = new List.from(s); - _element.$dom_className = Strings.join(list, ' '); + _element.$dom_className = s.join(' '); } } @@ -10208,13 +10438,61 @@ class FileList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, File)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(File element) => Collections.contains(this, element); + + void forEach(void f(File element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(File element)) => new MappedList(this, f); + + Iterable where(bool f(File element)) => new WhereIterable(this, f); + + bool every(bool f(File element)) => Collections.every(this, f); + + bool any(bool f(File element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(File value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(File value)) { + return new SkipWhileIterable(this, test); + } + + File firstMatching(bool test(File value), { File orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + File lastMatching(bool test(File value), {File orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + File singleMatching(bool test(File value)) { + return Collections.singleMatching(this, test); + } + + File elementAt(int index) { + return this[index]; + } + // From Collection: void add(File value) { @@ -10225,29 +10503,10 @@ class FileList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, File)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(File element) => Collections.contains(this, element); - - void forEach(void f(File element)) => Collections.forEach(this, f); - - Collection map(f(File element)) => Collections.map(this, [], f); - - Collection filter(bool f(File element)) => - Collections.filter(this, [], f); - - bool every(bool f(File element)) => Collections.every(this, f); - - bool some(bool f(File element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -10269,9 +10528,25 @@ class FileList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - File get first => this[0]; + File get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - File get last => this[length - 1]; + File get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + File get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + File min([int compare(File a, File b)]) => _Collections.minInList(this, compare); + + File max([int compare(File a, File b)]) => _Collections.maxInList(this, compare); File removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -10668,13 +10943,61 @@ class Float32Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(num element) => Collections.contains(this, element); + + void forEach(void f(num element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(num element)) => new MappedList(this, f); + + Iterable where(bool f(num element)) => new WhereIterable(this, f); + + bool every(bool f(num element)) => Collections.every(this, f); + + bool any(bool f(num element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(num value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(num value)) { + return new SkipWhileIterable(this, test); + } + + num firstMatching(bool test(num value), { num orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + num lastMatching(bool test(num value), {num orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + num singleMatching(bool test(num value)) { + return Collections.singleMatching(this, test); + } + + num elementAt(int index) { + return this[index]; + } + // From Collection: void add(num value) { @@ -10685,29 +11008,10 @@ class Float32Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(num element) => Collections.contains(this, element); - - void forEach(void f(num element)) => Collections.forEach(this, f); - - Collection map(f(num element)) => Collections.map(this, [], f); - - Collection filter(bool f(num element)) => - Collections.filter(this, [], f); - - bool every(bool f(num element)) => Collections.every(this, f); - - bool some(bool f(num element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -10729,9 +11033,25 @@ class Float32Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - num get first => this[0]; + num get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - num get last => this[length - 1]; + num get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + num get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + num min([int compare(num a, num b)]) => _Collections.minInList(this, compare); + + num max([int compare(num a, num b)]) => _Collections.maxInList(this, compare); num removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -10816,13 +11136,61 @@ class Float64Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(num element) => Collections.contains(this, element); + + void forEach(void f(num element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(num element)) => new MappedList(this, f); + + Iterable where(bool f(num element)) => new WhereIterable(this, f); + + bool every(bool f(num element)) => Collections.every(this, f); + + bool any(bool f(num element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(num value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(num value)) { + return new SkipWhileIterable(this, test); + } + + num firstMatching(bool test(num value), { num orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + num lastMatching(bool test(num value), {num orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + num singleMatching(bool test(num value)) { + return Collections.singleMatching(this, test); + } + + num elementAt(int index) { + return this[index]; + } + // From Collection: void add(num value) { @@ -10833,29 +11201,10 @@ class Float64Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, num)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(num element) => Collections.contains(this, element); - - void forEach(void f(num element)) => Collections.forEach(this, f); - - Collection map(f(num element)) => Collections.map(this, [], f); - - Collection filter(bool f(num element)) => - Collections.filter(this, [], f); - - bool every(bool f(num element)) => Collections.every(this, f); - - bool some(bool f(num element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -10877,9 +11226,25 @@ class Float64Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - num get first => this[0]; + num get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - num get last => this[length - 1]; + num get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + num get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + num min([int compare(num a, num b)]) => _Collections.minInList(this, compare); + + num max([int compare(num a, num b)]) => _Collections.maxInList(this, compare); num removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -11504,13 +11869,61 @@ class HtmlAllCollection extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -11521,29 +11934,10 @@ class HtmlAllCollection extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -11565,9 +11959,25 @@ class HtmlAllCollection extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -11632,13 +12042,61 @@ class HtmlCollection extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -11649,29 +12107,10 @@ class HtmlCollection extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -11693,9 +12132,25 @@ class HtmlCollection extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -13517,13 +13972,61 @@ class Int16Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -13534,29 +14037,10 @@ class Int16Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -13578,9 +14062,25 @@ class Int16Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -13665,13 +14165,61 @@ class Int32Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -13682,29 +14230,10 @@ class Int32Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -13726,9 +14255,25 @@ class Int32Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -13813,13 +14358,61 @@ class Int8Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -13830,29 +14423,10 @@ class Int8Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -13874,9 +14448,25 @@ class Int8Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -16139,13 +16729,61 @@ class NamedNodeMap extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -16156,29 +16794,10 @@ class NamedNodeMap extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -16200,9 +16819,25 @@ class NamedNodeMap extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -16400,8 +17035,30 @@ class _ChildNodeListLazy implements List { _ChildNodeListLazy(this._this); - Node get first => _this.$dom_firstChild; - Node get last => _this.$dom_lastChild; + Node get first { + Node result = _this.$dom_firstChild; + if (result == null) throw new StateError("No elements"); + return result; + } + Node get last { + Node result = _this.$dom_lastChild; + if (result == null) throw new StateError("No elements"); + return result; + } + Node get single { + int l = this.length; + if (l == 0) throw new StateError("No elements"); + if (l > 1) throw new StateError("More than one element"); + return _this.$dom_firstChild; + } + + Node min([int compare(Node a, Node b)]) { + return _Collections.minInList(this, compare); + } + + Node max([int compare(Node a, Node b)]) { + return _Collections.maxInList(this, compare); + } void add(Node value) { _this.$dom_appendChild(value); @@ -16412,8 +17069,8 @@ class _ChildNodeListLazy implements List { } - void addAll(Collection collection) { - for (Node node in collection) { + void addAll(Iterable iterable) { + for (Node node in iterable) { _this.$dom_appendChild(node); } } @@ -16442,7 +17099,7 @@ class _ChildNodeListLazy implements List { _this.$dom_replaceChild(value, this[index]); } - Iterator iterator() => _this.$dom_childNodes.iterator(); + Iterator get iterator => _this.$dom_childNodes.iterator; // TODO(jacobr): We can implement these methods much more efficiently by // looking up the nodeList only once instead of once per iteration. @@ -16455,19 +17112,56 @@ class _ChildNodeListLazy implements List { return Collections.reduce(this, initialValue, combine); } - Collection map(f(Node element)) => Collections.map(this, [], f); + String join([String separator]) { + return Collections.joinList(this, separator); + } - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); + List mappedBy(f(Node element)) => + new MappedList(this, f); + + Iterable where(bool f(Node element)) => + new WhereIterable(this, f); bool every(bool f(Node element)) => Collections.every(this, f); - bool some(bool f(Node element)) => Collections.some(this, f); + bool any(bool f(Node element)) => Collections.any(this, f); bool get isEmpty => this.length == 0; // From List: + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), {Node orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // TODO(jacobr): this could be implemented for child node lists. // The exception we throw here is misleading. void sort([int compare(Node a, Node b)]) { @@ -16809,13 +17503,61 @@ class NodeList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Node element) => Collections.contains(this, element); + + void forEach(void f(Node element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Node element)) => new MappedList(this, f); + + Iterable where(bool f(Node element)) => new WhereIterable(this, f); + + bool every(bool f(Node element)) => Collections.every(this, f); + + bool any(bool f(Node element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), { Node orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // From Collection: void add(Node value) { @@ -16826,29 +17568,10 @@ class NodeList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Node)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Node element) => Collections.contains(this, element); - - void forEach(void f(Node element)) => Collections.forEach(this, f); - - Collection map(f(Node element)) => Collections.map(this, [], f); - - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); - - bool every(bool f(Node element)) => Collections.every(this, f); - - bool some(bool f(Node element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -16870,9 +17593,25 @@ class NodeList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Node get first => this[0]; + Node get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Node get last => this[length - 1]; + Node get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Node get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Node min([int compare(Node a, Node b)]) => _Collections.minInList(this, compare); + + Node max([int compare(Node a, Node b)]) => _Collections.maxInList(this, compare); Node removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -19024,13 +19763,13 @@ class SelectElement extends _Element_Merged { // Override default options, since IE returns SelectElement itself and it // does not operate as a List. List get options { - return this.children.filter((e) => e is OptionElement); + return this.children.where((e) => e is OptionElement).toList(); } List get selectedOptions { // IE does not change the selected flag for single-selection items. if (this.multiple) { - return this.options.filter((o) => o.selected); + return this.options.where((o) => o.selected).toList(); } else { return [this.options[this.selectedIndex]]; } @@ -19241,13 +19980,61 @@ class SourceBufferList extends EventTarget implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SourceBuffer)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SourceBuffer element) => Collections.contains(this, element); + + void forEach(void f(SourceBuffer element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SourceBuffer element)) => new MappedList(this, f); + + Iterable where(bool f(SourceBuffer element)) => new WhereIterable(this, f); + + bool every(bool f(SourceBuffer element)) => Collections.every(this, f); + + bool any(bool f(SourceBuffer element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SourceBuffer value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SourceBuffer value)) { + return new SkipWhileIterable(this, test); + } + + SourceBuffer firstMatching(bool test(SourceBuffer value), { SourceBuffer orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SourceBuffer lastMatching(bool test(SourceBuffer value), {SourceBuffer orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SourceBuffer singleMatching(bool test(SourceBuffer value)) { + return Collections.singleMatching(this, test); + } + + SourceBuffer elementAt(int index) { + return this[index]; + } + // From Collection: void add(SourceBuffer value) { @@ -19258,29 +20045,10 @@ class SourceBufferList extends EventTarget implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SourceBuffer)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SourceBuffer element) => Collections.contains(this, element); - - void forEach(void f(SourceBuffer element)) => Collections.forEach(this, f); - - Collection map(f(SourceBuffer element)) => Collections.map(this, [], f); - - Collection filter(bool f(SourceBuffer element)) => - Collections.filter(this, [], f); - - bool every(bool f(SourceBuffer element)) => Collections.every(this, f); - - bool some(bool f(SourceBuffer element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -19302,9 +20070,25 @@ class SourceBufferList extends EventTarget implements List { return Lists.lastIndexOf(this, element, start); } - SourceBuffer get first => this[0]; + SourceBuffer get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SourceBuffer get last => this[length - 1]; + SourceBuffer get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SourceBuffer get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SourceBuffer min([int compare(SourceBuffer a, SourceBuffer b)]) => _Collections.minInList(this, compare); + + SourceBuffer max([int compare(SourceBuffer a, SourceBuffer b)]) => _Collections.maxInList(this, compare); SourceBuffer removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -19463,13 +20247,61 @@ class SpeechGrammarList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechGrammar)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SpeechGrammar element) => Collections.contains(this, element); + + void forEach(void f(SpeechGrammar element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SpeechGrammar element)) => new MappedList(this, f); + + Iterable where(bool f(SpeechGrammar element)) => new WhereIterable(this, f); + + bool every(bool f(SpeechGrammar element)) => Collections.every(this, f); + + bool any(bool f(SpeechGrammar element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SpeechGrammar value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SpeechGrammar value)) { + return new SkipWhileIterable(this, test); + } + + SpeechGrammar firstMatching(bool test(SpeechGrammar value), { SpeechGrammar orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SpeechGrammar lastMatching(bool test(SpeechGrammar value), {SpeechGrammar orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SpeechGrammar singleMatching(bool test(SpeechGrammar value)) { + return Collections.singleMatching(this, test); + } + + SpeechGrammar elementAt(int index) { + return this[index]; + } + // From Collection: void add(SpeechGrammar value) { @@ -19480,29 +20312,10 @@ class SpeechGrammarList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechGrammar)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SpeechGrammar element) => Collections.contains(this, element); - - void forEach(void f(SpeechGrammar element)) => Collections.forEach(this, f); - - Collection map(f(SpeechGrammar element)) => Collections.map(this, [], f); - - Collection filter(bool f(SpeechGrammar element)) => - Collections.filter(this, [], f); - - bool every(bool f(SpeechGrammar element)) => Collections.every(this, f); - - bool some(bool f(SpeechGrammar element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -19524,9 +20337,25 @@ class SpeechGrammarList extends NativeFieldWrapperClass1 implements List this[0]; + SpeechGrammar get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SpeechGrammar get last => this[length - 1]; + SpeechGrammar get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SpeechGrammar get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SpeechGrammar min([int compare(SpeechGrammar a, SpeechGrammar b)]) => _Collections.minInList(this, compare); + + SpeechGrammar max([int compare(SpeechGrammar a, SpeechGrammar b)]) => _Collections.maxInList(this, compare); SpeechGrammar removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -19962,13 +20791,61 @@ class SqlResultSetRowList extends NativeFieldWrapperClass1 implements List // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Map element) => Collections.contains(this, element); + + void forEach(void f(Map element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Map element)) => new MappedList(this, f); + + Iterable where(bool f(Map element)) => new WhereIterable(this, f); + + bool every(bool f(Map element)) => Collections.every(this, f); + + bool any(bool f(Map element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Map value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Map value)) { + return new SkipWhileIterable(this, test); + } + + Map firstMatching(bool test(Map value), { Map orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Map lastMatching(bool test(Map value), {Map orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Map singleMatching(bool test(Map value)) { + return Collections.singleMatching(this, test); + } + + Map elementAt(int index) { + return this[index]; + } + // From Collection: void add(Map value) { @@ -19979,29 +20856,10 @@ class SqlResultSetRowList extends NativeFieldWrapperClass1 implements List throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Map element) => Collections.contains(this, element); - - void forEach(void f(Map element)) => Collections.forEach(this, f); - - Collection map(f(Map element)) => Collections.map(this, [], f); - - Collection filter(bool f(Map element)) => - Collections.filter(this, [], f); - - bool every(bool f(Map element)) => Collections.every(this, f); - - bool some(bool f(Map element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -20023,9 +20881,25 @@ class SqlResultSetRowList extends NativeFieldWrapperClass1 implements List return Lists.lastIndexOf(this, element, start); } - Map get first => this[0]; + Map get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Map get last => this[length - 1]; + Map get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Map get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Map min([int compare(Map a, Map b)]) => _Collections.minInList(this, compare); + + Map max([int compare(Map a, Map b)]) => _Collections.maxInList(this, compare); Map removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -20098,7 +20972,7 @@ class SqlTransactionSync extends NativeFieldWrapperClass1 { class Storage extends NativeFieldWrapperClass1 implements Map { // TODO(nweiz): update this when maps support lazy iteration - bool containsValue(String value) => values.some((e) => e == value); + bool containsValue(String value) => values.any((e) => e == value); bool containsKey(String key) => $dom_getItem(key) != null; @@ -21134,13 +22008,61 @@ class TextTrackCueList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrackCue)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(TextTrackCue element) => Collections.contains(this, element); + + void forEach(void f(TextTrackCue element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(TextTrackCue element)) => new MappedList(this, f); + + Iterable where(bool f(TextTrackCue element)) => new WhereIterable(this, f); + + bool every(bool f(TextTrackCue element)) => Collections.every(this, f); + + bool any(bool f(TextTrackCue element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(TextTrackCue value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(TextTrackCue value)) { + return new SkipWhileIterable(this, test); + } + + TextTrackCue firstMatching(bool test(TextTrackCue value), { TextTrackCue orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + TextTrackCue lastMatching(bool test(TextTrackCue value), {TextTrackCue orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + TextTrackCue singleMatching(bool test(TextTrackCue value)) { + return Collections.singleMatching(this, test); + } + + TextTrackCue elementAt(int index) { + return this[index]; + } + // From Collection: void add(TextTrackCue value) { @@ -21151,29 +22073,10 @@ class TextTrackCueList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrackCue)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(TextTrackCue element) => Collections.contains(this, element); - - void forEach(void f(TextTrackCue element)) => Collections.forEach(this, f); - - Collection map(f(TextTrackCue element)) => Collections.map(this, [], f); - - Collection filter(bool f(TextTrackCue element)) => - Collections.filter(this, [], f); - - bool every(bool f(TextTrackCue element)) => Collections.every(this, f); - - bool some(bool f(TextTrackCue element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21195,9 +22098,25 @@ class TextTrackCueList extends NativeFieldWrapperClass1 implements List this[0]; + TextTrackCue get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - TextTrackCue get last => this[length - 1]; + TextTrackCue get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + TextTrackCue get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + TextTrackCue min([int compare(TextTrackCue a, TextTrackCue b)]) => _Collections.minInList(this, compare); + + TextTrackCue max([int compare(TextTrackCue a, TextTrackCue b)]) => _Collections.maxInList(this, compare); TextTrackCue removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21262,13 +22181,61 @@ class TextTrackList extends EventTarget implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrack)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(TextTrack element) => Collections.contains(this, element); + + void forEach(void f(TextTrack element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(TextTrack element)) => new MappedList(this, f); + + Iterable where(bool f(TextTrack element)) => new WhereIterable(this, f); + + bool every(bool f(TextTrack element)) => Collections.every(this, f); + + bool any(bool f(TextTrack element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(TextTrack value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(TextTrack value)) { + return new SkipWhileIterable(this, test); + } + + TextTrack firstMatching(bool test(TextTrack value), { TextTrack orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + TextTrack lastMatching(bool test(TextTrack value), {TextTrack orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + TextTrack singleMatching(bool test(TextTrack value)) { + return Collections.singleMatching(this, test); + } + + TextTrack elementAt(int index) { + return this[index]; + } + // From Collection: void add(TextTrack value) { @@ -21279,29 +22246,10 @@ class TextTrackList extends EventTarget implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, TextTrack)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(TextTrack element) => Collections.contains(this, element); - - void forEach(void f(TextTrack element)) => Collections.forEach(this, f); - - Collection map(f(TextTrack element)) => Collections.map(this, [], f); - - Collection filter(bool f(TextTrack element)) => - Collections.filter(this, [], f); - - bool every(bool f(TextTrack element)) => Collections.every(this, f); - - bool some(bool f(TextTrack element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21323,9 +22271,25 @@ class TextTrackList extends EventTarget implements List { return Lists.lastIndexOf(this, element, start); } - TextTrack get first => this[0]; + TextTrack get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - TextTrack get last => this[length - 1]; + TextTrack get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + TextTrack get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + TextTrack min([int compare(TextTrack a, TextTrack b)]) => _Collections.minInList(this, compare); + + TextTrack max([int compare(TextTrack a, TextTrack b)]) => _Collections.maxInList(this, compare); TextTrack removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21554,13 +22518,61 @@ class TouchList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Touch)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Touch element) => Collections.contains(this, element); + + void forEach(void f(Touch element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Touch element)) => new MappedList(this, f); + + Iterable where(bool f(Touch element)) => new WhereIterable(this, f); + + bool every(bool f(Touch element)) => Collections.every(this, f); + + bool any(bool f(Touch element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Touch value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Touch value)) { + return new SkipWhileIterable(this, test); + } + + Touch firstMatching(bool test(Touch value), { Touch orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Touch lastMatching(bool test(Touch value), {Touch orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Touch singleMatching(bool test(Touch value)) { + return Collections.singleMatching(this, test); + } + + Touch elementAt(int index) { + return this[index]; + } + // From Collection: void add(Touch value) { @@ -21571,29 +22583,10 @@ class TouchList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Touch)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Touch element) => Collections.contains(this, element); - - void forEach(void f(Touch element)) => Collections.forEach(this, f); - - Collection map(f(Touch element)) => Collections.map(this, [], f); - - Collection filter(bool f(Touch element)) => - Collections.filter(this, [], f); - - bool every(bool f(Touch element)) => Collections.every(this, f); - - bool some(bool f(Touch element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -21615,9 +22608,25 @@ class TouchList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Touch get first => this[0]; + Touch get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Touch get last => this[length - 1]; + Touch get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Touch get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Touch min([int compare(Touch a, Touch b)]) => _Collections.minInList(this, compare); + + Touch max([int compare(Touch a, Touch b)]) => _Collections.maxInList(this, compare); Touch removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -21945,13 +22954,61 @@ class Uint16Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -21962,29 +23019,10 @@ class Uint16Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -22006,9 +23044,25 @@ class Uint16Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -22093,13 +23147,61 @@ class Uint32Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -22110,29 +23212,10 @@ class Uint32Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -22154,9 +23237,25 @@ class Uint32Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -22241,13 +23340,61 @@ class Uint8Array extends ArrayBufferView implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(int element) => Collections.contains(this, element); + + void forEach(void f(int element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(int element)) => new MappedList(this, f); + + Iterable where(bool f(int element)) => new WhereIterable(this, f); + + bool every(bool f(int element)) => Collections.every(this, f); + + bool any(bool f(int element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(int value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(int value)) { + return new SkipWhileIterable(this, test); + } + + int firstMatching(bool test(int value), { int orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + int lastMatching(bool test(int value), {int orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + int singleMatching(bool test(int value)) { + return Collections.singleMatching(this, test); + } + + int elementAt(int index) { + return this[index]; + } + // From Collection: void add(int value) { @@ -22258,29 +23405,10 @@ class Uint8Array extends ArrayBufferView implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, int)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(int element) => Collections.contains(this, element); - - void forEach(void f(int element)) => Collections.forEach(this, f); - - Collection map(f(int element)) => Collections.map(this, [], f); - - Collection filter(bool f(int element)) => - Collections.filter(this, [], f); - - bool every(bool f(int element)) => Collections.every(this, f); - - bool some(bool f(int element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -22302,9 +23430,25 @@ class Uint8Array extends ArrayBufferView implements List { return Lists.lastIndexOf(this, element, start); } - int get first => this[0]; + int get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - int get last => this[length - 1]; + int get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + int get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + int min([int compare(int a, int b)]) => _Collections.minInList(this, compare); + + int max([int compare(int a, int b)]) => _Collections.maxInList(this, compare); int removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -24506,7 +25650,7 @@ class Window extends EventTarget implements WindowBase { * registered under [name]. */ lookupPort(String name) { - var port = JSON.parse(document.documentElement.attributes['dart-port:$name']); + var port = json.parse(document.documentElement.attributes['dart-port:$name']); return _deserialize(port); } @@ -24517,7 +25661,7 @@ class Window extends EventTarget implements WindowBase { */ registerPort(String name, var port) { var serialized = _serialize(port); - document.documentElement.attributes['dart-port:$name'] = JSON.stringify(serialized); + document.documentElement.attributes['dart-port:$name'] = json.stringify(serialized); } Window.internal() : super.internal(); @@ -25614,13 +26758,61 @@ class _ClientRectList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ClientRect)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(ClientRect element) => Collections.contains(this, element); + + void forEach(void f(ClientRect element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(ClientRect element)) => new MappedList(this, f); + + Iterable where(bool f(ClientRect element)) => new WhereIterable(this, f); + + bool every(bool f(ClientRect element)) => Collections.every(this, f); + + bool any(bool f(ClientRect element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(ClientRect value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(ClientRect value)) { + return new SkipWhileIterable(this, test); + } + + ClientRect firstMatching(bool test(ClientRect value), { ClientRect orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + ClientRect lastMatching(bool test(ClientRect value), {ClientRect orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + ClientRect singleMatching(bool test(ClientRect value)) { + return Collections.singleMatching(this, test); + } + + ClientRect elementAt(int index) { + return this[index]; + } + // From Collection: void add(ClientRect value) { @@ -25631,29 +26823,10 @@ class _ClientRectList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ClientRect)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(ClientRect element) => Collections.contains(this, element); - - void forEach(void f(ClientRect element)) => Collections.forEach(this, f); - - Collection map(f(ClientRect element)) => Collections.map(this, [], f); - - Collection filter(bool f(ClientRect element)) => - Collections.filter(this, [], f); - - bool every(bool f(ClientRect element)) => Collections.every(this, f); - - bool some(bool f(ClientRect element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -25675,9 +26848,25 @@ class _ClientRectList extends NativeFieldWrapperClass1 implements List this[0]; + ClientRect get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - ClientRect get last => this[length - 1]; + ClientRect get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + ClientRect get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + ClientRect min([int compare(ClientRect a, ClientRect b)]) => _Collections.minInList(this, compare); + + ClientRect max([int compare(ClientRect a, ClientRect b)]) => _Collections.maxInList(this, compare); ClientRect removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -25734,13 +26923,61 @@ class _CssRuleList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssRule)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(CssRule element) => Collections.contains(this, element); + + void forEach(void f(CssRule element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(CssRule element)) => new MappedList(this, f); + + Iterable where(bool f(CssRule element)) => new WhereIterable(this, f); + + bool every(bool f(CssRule element)) => Collections.every(this, f); + + bool any(bool f(CssRule element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(CssRule value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(CssRule value)) { + return new SkipWhileIterable(this, test); + } + + CssRule firstMatching(bool test(CssRule value), { CssRule orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + CssRule lastMatching(bool test(CssRule value), {CssRule orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + CssRule singleMatching(bool test(CssRule value)) { + return Collections.singleMatching(this, test); + } + + CssRule elementAt(int index) { + return this[index]; + } + // From Collection: void add(CssRule value) { @@ -25751,29 +26988,10 @@ class _CssRuleList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssRule)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(CssRule element) => Collections.contains(this, element); - - void forEach(void f(CssRule element)) => Collections.forEach(this, f); - - Collection map(f(CssRule element)) => Collections.map(this, [], f); - - Collection filter(bool f(CssRule element)) => - Collections.filter(this, [], f); - - bool every(bool f(CssRule element)) => Collections.every(this, f); - - bool some(bool f(CssRule element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -25795,9 +27013,25 @@ class _CssRuleList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - CssRule get first => this[0]; + CssRule get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - CssRule get last => this[length - 1]; + CssRule get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + CssRule get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + CssRule min([int compare(CssRule a, CssRule b)]) => _Collections.minInList(this, compare); + + CssRule max([int compare(CssRule a, CssRule b)]) => _Collections.maxInList(this, compare); CssRule removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -25854,13 +27088,61 @@ class _CssValueList extends CssValue implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssValue)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(CssValue element) => Collections.contains(this, element); + + void forEach(void f(CssValue element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(CssValue element)) => new MappedList(this, f); + + Iterable where(bool f(CssValue element)) => new WhereIterable(this, f); + + bool every(bool f(CssValue element)) => Collections.every(this, f); + + bool any(bool f(CssValue element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(CssValue value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(CssValue value)) { + return new SkipWhileIterable(this, test); + } + + CssValue firstMatching(bool test(CssValue value), { CssValue orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + CssValue lastMatching(bool test(CssValue value), {CssValue orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + CssValue singleMatching(bool test(CssValue value)) { + return Collections.singleMatching(this, test); + } + + CssValue elementAt(int index) { + return this[index]; + } + // From Collection: void add(CssValue value) { @@ -25871,29 +27153,10 @@ class _CssValueList extends CssValue implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, CssValue)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(CssValue element) => Collections.contains(this, element); - - void forEach(void f(CssValue element)) => Collections.forEach(this, f); - - Collection map(f(CssValue element)) => Collections.map(this, [], f); - - Collection filter(bool f(CssValue element)) => - Collections.filter(this, [], f); - - bool every(bool f(CssValue element)) => Collections.every(this, f); - - bool some(bool f(CssValue element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -25915,9 +27178,25 @@ class _CssValueList extends CssValue implements List { return Lists.lastIndexOf(this, element, start); } - CssValue get first => this[0]; + CssValue get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - CssValue get last => this[length - 1]; + CssValue get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + CssValue get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + CssValue min([int compare(CssValue a, CssValue b)]) => _Collections.minInList(this, compare); + + CssValue max([int compare(CssValue a, CssValue b)]) => _Collections.maxInList(this, compare); CssValue removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26110,13 +27389,61 @@ class _EntryArray extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Entry)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Entry element) => Collections.contains(this, element); + + void forEach(void f(Entry element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Entry element)) => new MappedList(this, f); + + Iterable where(bool f(Entry element)) => new WhereIterable(this, f); + + bool every(bool f(Entry element)) => Collections.every(this, f); + + bool any(bool f(Entry element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Entry value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Entry value)) { + return new SkipWhileIterable(this, test); + } + + Entry firstMatching(bool test(Entry value), { Entry orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Entry lastMatching(bool test(Entry value), {Entry orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Entry singleMatching(bool test(Entry value)) { + return Collections.singleMatching(this, test); + } + + Entry elementAt(int index) { + return this[index]; + } + // From Collection: void add(Entry value) { @@ -26127,29 +27454,10 @@ class _EntryArray extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Entry)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Entry element) => Collections.contains(this, element); - - void forEach(void f(Entry element)) => Collections.forEach(this, f); - - Collection map(f(Entry element)) => Collections.map(this, [], f); - - Collection filter(bool f(Entry element)) => - Collections.filter(this, [], f); - - bool every(bool f(Entry element)) => Collections.every(this, f); - - bool some(bool f(Entry element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26171,9 +27479,25 @@ class _EntryArray extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Entry get first => this[0]; + Entry get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Entry get last => this[length - 1]; + Entry get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Entry get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Entry min([int compare(Entry a, Entry b)]) => _Collections.minInList(this, compare); + + Entry max([int compare(Entry a, Entry b)]) => _Collections.maxInList(this, compare); Entry removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26230,13 +27554,61 @@ class _EntryArraySync extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, EntrySync)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(EntrySync element) => Collections.contains(this, element); + + void forEach(void f(EntrySync element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(EntrySync element)) => new MappedList(this, f); + + Iterable where(bool f(EntrySync element)) => new WhereIterable(this, f); + + bool every(bool f(EntrySync element)) => Collections.every(this, f); + + bool any(bool f(EntrySync element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(EntrySync value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(EntrySync value)) { + return new SkipWhileIterable(this, test); + } + + EntrySync firstMatching(bool test(EntrySync value), { EntrySync orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + EntrySync lastMatching(bool test(EntrySync value), {EntrySync orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + EntrySync singleMatching(bool test(EntrySync value)) { + return Collections.singleMatching(this, test); + } + + EntrySync elementAt(int index) { + return this[index]; + } + // From Collection: void add(EntrySync value) { @@ -26247,29 +27619,10 @@ class _EntryArraySync extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, EntrySync)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(EntrySync element) => Collections.contains(this, element); - - void forEach(void f(EntrySync element)) => Collections.forEach(this, f); - - Collection map(f(EntrySync element)) => Collections.map(this, [], f); - - Collection filter(bool f(EntrySync element)) => - Collections.filter(this, [], f); - - bool every(bool f(EntrySync element)) => Collections.every(this, f); - - bool some(bool f(EntrySync element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26291,9 +27644,25 @@ class _EntryArraySync extends NativeFieldWrapperClass1 implements List this[0]; + EntrySync get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - EntrySync get last => this[length - 1]; + EntrySync get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + EntrySync get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + EntrySync min([int compare(EntrySync a, EntrySync b)]) => _Collections.minInList(this, compare); + + EntrySync max([int compare(EntrySync a, EntrySync b)]) => _Collections.maxInList(this, compare); EntrySync removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26350,13 +27719,61 @@ class _GamepadList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Gamepad)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Gamepad element) => Collections.contains(this, element); + + void forEach(void f(Gamepad element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Gamepad element)) => new MappedList(this, f); + + Iterable where(bool f(Gamepad element)) => new WhereIterable(this, f); + + bool every(bool f(Gamepad element)) => Collections.every(this, f); + + bool any(bool f(Gamepad element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Gamepad value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Gamepad value)) { + return new SkipWhileIterable(this, test); + } + + Gamepad firstMatching(bool test(Gamepad value), { Gamepad orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Gamepad lastMatching(bool test(Gamepad value), {Gamepad orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Gamepad singleMatching(bool test(Gamepad value)) { + return Collections.singleMatching(this, test); + } + + Gamepad elementAt(int index) { + return this[index]; + } + // From Collection: void add(Gamepad value) { @@ -26367,29 +27784,10 @@ class _GamepadList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Gamepad)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Gamepad element) => Collections.contains(this, element); - - void forEach(void f(Gamepad element)) => Collections.forEach(this, f); - - Collection map(f(Gamepad element)) => Collections.map(this, [], f); - - Collection filter(bool f(Gamepad element)) => - Collections.filter(this, [], f); - - bool every(bool f(Gamepad element)) => Collections.every(this, f); - - bool some(bool f(Gamepad element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26411,9 +27809,25 @@ class _GamepadList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Gamepad get first => this[0]; + Gamepad get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Gamepad get last => this[length - 1]; + Gamepad get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Gamepad get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Gamepad min([int compare(Gamepad a, Gamepad b)]) => _Collections.minInList(this, compare); + + Gamepad max([int compare(Gamepad a, Gamepad b)]) => _Collections.maxInList(this, compare); Gamepad removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26470,13 +27884,61 @@ class _MediaStreamList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, MediaStream)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(MediaStream element) => Collections.contains(this, element); + + void forEach(void f(MediaStream element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(MediaStream element)) => new MappedList(this, f); + + Iterable where(bool f(MediaStream element)) => new WhereIterable(this, f); + + bool every(bool f(MediaStream element)) => Collections.every(this, f); + + bool any(bool f(MediaStream element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(MediaStream value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(MediaStream value)) { + return new SkipWhileIterable(this, test); + } + + MediaStream firstMatching(bool test(MediaStream value), { MediaStream orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + MediaStream lastMatching(bool test(MediaStream value), {MediaStream orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + MediaStream singleMatching(bool test(MediaStream value)) { + return Collections.singleMatching(this, test); + } + + MediaStream elementAt(int index) { + return this[index]; + } + // From Collection: void add(MediaStream value) { @@ -26487,29 +27949,10 @@ class _MediaStreamList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, MediaStream)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(MediaStream element) => Collections.contains(this, element); - - void forEach(void f(MediaStream element)) => Collections.forEach(this, f); - - Collection map(f(MediaStream element)) => Collections.map(this, [], f); - - Collection filter(bool f(MediaStream element)) => - Collections.filter(this, [], f); - - bool every(bool f(MediaStream element)) => Collections.every(this, f); - - bool some(bool f(MediaStream element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26531,9 +27974,25 @@ class _MediaStreamList extends NativeFieldWrapperClass1 implements List this[0]; + MediaStream get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - MediaStream get last => this[length - 1]; + MediaStream get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + MediaStream get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + MediaStream min([int compare(MediaStream a, MediaStream b)]) => _Collections.minInList(this, compare); + + MediaStream max([int compare(MediaStream a, MediaStream b)]) => _Collections.maxInList(this, compare); MediaStream removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26590,13 +28049,61 @@ class _SpeechInputResultList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechInputResult)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SpeechInputResult element) => Collections.contains(this, element); + + void forEach(void f(SpeechInputResult element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SpeechInputResult element)) => new MappedList(this, f); + + Iterable where(bool f(SpeechInputResult element)) => new WhereIterable(this, f); + + bool every(bool f(SpeechInputResult element)) => Collections.every(this, f); + + bool any(bool f(SpeechInputResult element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SpeechInputResult value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SpeechInputResult value)) { + return new SkipWhileIterable(this, test); + } + + SpeechInputResult firstMatching(bool test(SpeechInputResult value), { SpeechInputResult orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SpeechInputResult lastMatching(bool test(SpeechInputResult value), {SpeechInputResult orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SpeechInputResult singleMatching(bool test(SpeechInputResult value)) { + return Collections.singleMatching(this, test); + } + + SpeechInputResult elementAt(int index) { + return this[index]; + } + // From Collection: void add(SpeechInputResult value) { @@ -26607,29 +28114,10 @@ class _SpeechInputResultList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechInputResult)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SpeechInputResult element) => Collections.contains(this, element); - - void forEach(void f(SpeechInputResult element)) => Collections.forEach(this, f); - - Collection map(f(SpeechInputResult element)) => Collections.map(this, [], f); - - Collection filter(bool f(SpeechInputResult element)) => - Collections.filter(this, [], f); - - bool every(bool f(SpeechInputResult element)) => Collections.every(this, f); - - bool some(bool f(SpeechInputResult element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26651,9 +28139,25 @@ class _SpeechInputResultList extends NativeFieldWrapperClass1 implements List this[0]; + SpeechInputResult get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SpeechInputResult get last => this[length - 1]; + SpeechInputResult get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SpeechInputResult get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SpeechInputResult min([int compare(SpeechInputResult a, SpeechInputResult b)]) => _Collections.minInList(this, compare); + + SpeechInputResult max([int compare(SpeechInputResult a, SpeechInputResult b)]) => _Collections.maxInList(this, compare); SpeechInputResult removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26710,13 +28214,61 @@ class _SpeechRecognitionResultList extends NativeFieldWrapperClass1 implements L // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechRecognitionResult)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(SpeechRecognitionResult element) => Collections.contains(this, element); + + void forEach(void f(SpeechRecognitionResult element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(SpeechRecognitionResult element)) => new MappedList(this, f); + + Iterable where(bool f(SpeechRecognitionResult element)) => new WhereIterable(this, f); + + bool every(bool f(SpeechRecognitionResult element)) => Collections.every(this, f); + + bool any(bool f(SpeechRecognitionResult element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(SpeechRecognitionResult value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(SpeechRecognitionResult value)) { + return new SkipWhileIterable(this, test); + } + + SpeechRecognitionResult firstMatching(bool test(SpeechRecognitionResult value), { SpeechRecognitionResult orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + SpeechRecognitionResult lastMatching(bool test(SpeechRecognitionResult value), {SpeechRecognitionResult orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + SpeechRecognitionResult singleMatching(bool test(SpeechRecognitionResult value)) { + return Collections.singleMatching(this, test); + } + + SpeechRecognitionResult elementAt(int index) { + return this[index]; + } + // From Collection: void add(SpeechRecognitionResult value) { @@ -26727,29 +28279,10 @@ class _SpeechRecognitionResultList extends NativeFieldWrapperClass1 implements L throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, SpeechRecognitionResult)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(SpeechRecognitionResult element) => Collections.contains(this, element); - - void forEach(void f(SpeechRecognitionResult element)) => Collections.forEach(this, f); - - Collection map(f(SpeechRecognitionResult element)) => Collections.map(this, [], f); - - Collection filter(bool f(SpeechRecognitionResult element)) => - Collections.filter(this, [], f); - - bool every(bool f(SpeechRecognitionResult element)) => Collections.every(this, f); - - bool some(bool f(SpeechRecognitionResult element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26771,9 +28304,25 @@ class _SpeechRecognitionResultList extends NativeFieldWrapperClass1 implements L return Lists.lastIndexOf(this, element, start); } - SpeechRecognitionResult get first => this[0]; + SpeechRecognitionResult get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - SpeechRecognitionResult get last => this[length - 1]; + SpeechRecognitionResult get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + SpeechRecognitionResult get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + SpeechRecognitionResult min([int compare(SpeechRecognitionResult a, SpeechRecognitionResult b)]) => _Collections.minInList(this, compare); + + SpeechRecognitionResult max([int compare(SpeechRecognitionResult a, SpeechRecognitionResult b)]) => _Collections.maxInList(this, compare); SpeechRecognitionResult removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -26830,13 +28379,61 @@ class _StyleSheetList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, StyleSheet)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(StyleSheet element) => Collections.contains(this, element); + + void forEach(void f(StyleSheet element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(StyleSheet element)) => new MappedList(this, f); + + Iterable where(bool f(StyleSheet element)) => new WhereIterable(this, f); + + bool every(bool f(StyleSheet element)) => Collections.every(this, f); + + bool any(bool f(StyleSheet element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(StyleSheet value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(StyleSheet value)) { + return new SkipWhileIterable(this, test); + } + + StyleSheet firstMatching(bool test(StyleSheet value), { StyleSheet orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + StyleSheet lastMatching(bool test(StyleSheet value), {StyleSheet orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + StyleSheet singleMatching(bool test(StyleSheet value)) { + return Collections.singleMatching(this, test); + } + + StyleSheet elementAt(int index) { + return this[index]; + } + // From Collection: void add(StyleSheet value) { @@ -26847,29 +28444,10 @@ class _StyleSheetList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, StyleSheet)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(StyleSheet element) => Collections.contains(this, element); - - void forEach(void f(StyleSheet element)) => Collections.forEach(this, f); - - Collection map(f(StyleSheet element)) => Collections.map(this, [], f); - - Collection filter(bool f(StyleSheet element)) => - Collections.filter(this, [], f); - - bool every(bool f(StyleSheet element)) => Collections.every(this, f); - - bool some(bool f(StyleSheet element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -26891,9 +28469,25 @@ class _StyleSheetList extends NativeFieldWrapperClass1 implements List this[0]; + StyleSheet get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - StyleSheet get last => this[length - 1]; + StyleSheet get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + StyleSheet get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + StyleSheet min([int compare(StyleSheet a, StyleSheet b)]) => _Collections.minInList(this, compare); + + StyleSheet max([int compare(StyleSheet a, StyleSheet b)]) => _Collections.maxInList(this, compare); StyleSheet removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -27087,7 +28681,7 @@ class _DataAttributeMap implements Map { // interface Map // TODO: Use lazy iterator when it is available on Map. - bool containsValue(String value) => values.some((v) => v == value); + bool containsValue(String value) => values.any((v) => v == value); bool containsKey(String key) => $dom_attributes.containsKey(_attr(key)); @@ -27310,7 +28904,7 @@ abstract class CssClassSet implements Set { bool get frozen => false; // interface Iterable - BEGIN - Iterator iterator() => readClasses().iterator(); + Iterator get iterator => readClasses().iterator; // interface Iterable - END // interface Collection - BEGIN @@ -27318,13 +28912,15 @@ abstract class CssClassSet implements Set { readClasses().forEach(f); } - Collection map(f(String element)) => readClasses().map(f); + String join([String separator]) => readClasses().join(separator); - Collection filter(bool f(String element)) => readClasses().filter(f); + Iterable mappedBy(f(String element)) => readClasses().mappedBy(f); + + Iterable where(bool f(String element)) => readClasses().where(f); bool every(bool f(String element)) => readClasses().every(f); - bool some(bool f(String element)) => readClasses().some(f); + bool any(bool f(String element)) => readClasses().any(f); bool get isEmpty => readClasses().isEmpty; @@ -27352,13 +28948,13 @@ abstract class CssClassSet implements Set { return result; } - void addAll(Collection collection) { + void addAll(Iterable iterable) { // TODO - see comment above about validation - _modify((s) => s.addAll(collection)); + _modify((s) => s.addAll(iterable)); } - void removeAll(Collection collection) { - _modify((s) => s.removeAll(collection)); + void removeAll(Iterable iterable) { + _modify((s) => s.removeAll(iterable)); } bool isSubsetOf(Collection collection) => @@ -27561,7 +29157,7 @@ class KeyboardEventController { /** Determine if caps lock is one of the currently depressed keys. */ bool get _capsLockOn => - _keyDownList.some((var element) => element.keyCode == KeyCode.CAPS_LOCK); + _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); /** * Given the previously recorded keydown key codes, see if we can determine @@ -27790,7 +29386,7 @@ class KeyboardEventController { // keyCode/which for non printable keys. e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]; } - e._shadowAltKey = _keyDownList.some((var element) => element.altKey); + e._shadowAltKey = _keyDownList.any((var element) => element.altKey); _dispatch(e); } @@ -27804,7 +29400,8 @@ class KeyboardEventController { } } if (toRemove != null) { - _keyDownList = _keyDownList.filter((element) => element != toRemove); + _keyDownList = + _keyDownList.where((element) => element != toRemove).toList(); } else if (_keyDownList.length > 0) { // This happens when we've reached some international keyboard case we // haven't accounted for or we haven't correctly eliminated all browser @@ -29076,7 +30673,7 @@ class _RemoteSendPortSync implements SendPortSync { var source = '$target-result'; var result = null; var listener = (Event e) { - result = JSON.parse(_getPortSyncEventData(e)); + result = json.parse(_getPortSyncEventData(e)); }; window.on[source].add(listener); _dispatchEvent(target, [source, message]); @@ -29148,7 +30745,7 @@ class ReceivePortSync { _callback = callback; if (_listener == null) { _listener = (Event e) { - var data = JSON.parse(_getPortSyncEventData(e)); + var data = json.parse(_getPortSyncEventData(e)); var replyTo = data[0]; var message = _deserialize(data[1]); var result = _callback(message); @@ -29179,7 +30776,7 @@ class ReceivePortSync { get _isolateId => ReceivePortSync._isolateId; void _dispatchEvent(String receiver, var message) { - var event = new CustomEvent(receiver, false, false, JSON.stringify(message)); + var event = new CustomEvent(receiver, false, false, json.stringify(message)); window.$dom_dispatchEvent(event); } @@ -29474,15 +31071,15 @@ abstract class _Serializer extends _MessageTraverser { int id = _nextFreeRefId++; _visited[map] = id; - var keys = _serializeList(map.keys); - var values = _serializeList(map.values); + var keys = _serializeList(map.keys.toList()); + var values = _serializeList(map.values.toList()); // TODO(floitsch): we are losing the generic type. return ['map', id, keys, values]; } _serializeList(List list) { int len = list.length; - var result = new List(len); + var result = new List.fixedLength(len); for (int i = 0; i < len; i++) { result[i] = _dispatch(list[i]); } @@ -29588,33 +31185,55 @@ class Testing { // Iterator for arrays with fixed size. -class FixedSizeListIterator extends _VariableSizeListIterator { +class FixedSizeListIterator implements Iterator { + final List _array; + final int _length; // Cache array length for faster access. + int _position; + T _current; + FixedSizeListIterator(List array) - : super(array), + : _array = array, + _position = -1, _length = array.length; - bool get hasNext => _length > _pos; + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; + } + _current = null; + _position = _length; + return false; + } - final int _length; // Cache array length for faster access. + T get current => _current; } // Iterator for arrays with variable size. class _VariableSizeListIterator implements Iterator { + final List _array; + int _position; + T _current; + _VariableSizeListIterator(List array) : _array = array, - _pos = 0; + _position = -1; - bool get hasNext => _array.length > _pos; - - T next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _array.length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; } - return _array[_pos++]; + _current = null; + _position = _array.length; + return false; } - final List _array; - int _pos; + T get current => _current; } // 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 @@ -29655,7 +31274,7 @@ class _Utils { static List convertToList(List list) { // FIXME: [possible optimization]: do not copy the array if Dart_IsArray is fine w/ it. final length = list.length; - List result = new List(length); + List result = new List.fixedLength(length); result.setRange(0, length, list); return result; } diff --git a/sdk/lib/html/html_common/filtered_element_list.dart b/sdk/lib/html/html_common/filtered_element_list.dart index 7486555286c..39a311c3b87 100644 --- a/sdk/lib/html/html_common/filtered_element_list.dart +++ b/sdk/lib/html/html_common/filtered_element_list.dart @@ -25,9 +25,10 @@ class FilteredElementList implements List { // We can't memoize this, since it's possible that children will be messed // with externally to this class. // - // TODO(nweiz): Do we really need to copy the list to make the types work out? + // TODO(nweiz): we don't always need to create a new list. For example + // forEach, every, any, ... could directly work on the _childNodes. List get _filtered => - new List.from(_childNodes.filter((n) => n is Element)); + new List.from(_childNodes.where((n) => n is Element)); void forEach(void f(Element element)) { _filtered.forEach(f); @@ -48,12 +49,16 @@ class FilteredElementList implements List { removeRange(newLength, len - newLength); } + String join([String separator]) => _filtered.join(separator); + void add(Element value) { _childNodes.add(value); } - void addAll(Collection collection) { - collection.forEach(add); + void addAll(Iterable iterable) { + for (Element element in iterable) { + add(element); + } } void addLast(Element value) { @@ -94,6 +99,9 @@ class FilteredElementList implements List { return result; } + Iterable mappedBy(f(Element element)) => _filtered.mappedBy(f); + Iterable where(bool f(Element element)) => _filtered.where(f); + Element removeAt(int index) { final result = this[index]; result.remove(); @@ -104,14 +112,29 @@ class FilteredElementList implements List { dynamic combine(dynamic previousValue, Element element)) { return Collections.reduce(this, initialValue, combine); } - Collection map(f(Element element)) => _filtered.map(f); - Collection filter(bool f(Element element)) => _filtered.filter(f); bool every(bool f(Element element)) => _filtered.every(f); - bool some(bool f(Element element)) => _filtered.some(f); + bool any(bool f(Element element)) => _filtered.any(f); + Element firstMatching(bool test(Element value), {Element orElse()}) { + return _filtered.firstMatching(test, orElse: orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return _filtered.lastMatching(test, orElse: orElse); + } + + Element singleMatching(bool test(Element value)) { + return _filtered.singleMatching(test); + } + + E elementAt(int index) { + return this[index]; + } + + bool get isEmpty => _filtered.isEmpty; int get length => _filtered.length; Element operator [](int index) => _filtered[index]; - Iterator iterator() => _filtered.iterator(); + Iterator get iterator => _filtered.iterator; List getRange(int start, int rangeLength) => _filtered.getRange(start, rangeLength); int indexOf(Element element, [int start = 0]) => @@ -122,7 +145,29 @@ class FilteredElementList implements List { return _filtered.lastIndexOf(element, start); } + Iterable take(int n) { + return new TakeIterable(this, n); + } + + Iterable takeWhile(bool test(Element value)) { + return new TakeWhileIterable(this, test); + } + + Iterable skip(int n) { + return new SkipIterable(this, n); + } + + Iterable skipWhile(bool test(Element value)) { + return new SkipWhileIterable(this, test); + } + Element get first => _filtered.first; Element get last => _filtered.last; + + Element get single => _filtered.single; + + Element min([int compare(Element a, Element b)]) => _filtered.min(compare); + + Element max([int compare(Element a, Element b)]) => _filtered.max(compare); } diff --git a/sdk/lib/html/html_common/lists.dart b/sdk/lib/html/html_common/lists.dart index 874039e05c3..03cc29e5ccd 100644 --- a/sdk/lib/html/html_common/lists.dart +++ b/sdk/lib/html/html_common/lists.dart @@ -66,4 +66,22 @@ class Lists { } return accumulator; } + + static String join(List list, [String separator]) { + if (list.isEmpty) return ""; + if (list.length == 1) return "${list[0]}"; + StringBuffer buffer = new StringBuffer(); + if (separator == null || separator == "") { + for (int i = 0; i < list.length; i++) { + buffer.add("${list[i]}"); + } + } else { + buffer.add("${list[0]}"); + for (int i = 1; i < list.length; i++) { + buffer.add(separator); + buffer.add("${list[i]}"); + } + } + return buffer.toString(); + } } diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart index 8017e956542..08ed648ac72 100644 --- a/sdk/lib/io/directory_impl.dart +++ b/sdk/lib/io/directory_impl.dart @@ -31,10 +31,10 @@ class _Directory implements Directory { Future exists() { _ensureDirectoryService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = EXISTS_REQUEST; request[1] = _path; - return _directoryService.call(request).transform((response) { + return _directoryService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionOrErrorFromResponse(response, "Exists failed"); } @@ -60,13 +60,13 @@ class _Directory implements Directory { var notFound = dirsToCreate.length; for (var i = 0; i < dirsToCreate.length; i++) { if (future == null) { - future = dirsToCreate[i].exists().transform((e) => e ? i : notFound); + future = dirsToCreate[i].exists().then((e) => e ? i : notFound); } else { - future = future.chain((index) { + future = future.then((index) { if (index != notFound) { return new Future.immediate(index); } - return dirsToCreate[i].exists().transform((e) => e ? i : notFound); + return dirsToCreate[i].exists().then((e) => e ? i : notFound); }); } } @@ -88,13 +88,13 @@ class _Directory implements Directory { dirsToCreate.add(new Directory.fromPath(path)); path = path.directoryPath; } - return _computeExistingIndex(dirsToCreate).chain((index) { + return _computeExistingIndex(dirsToCreate).then((index) { var future; for (var i = index - 1; i >= 0 ; i--) { if (future == null) { future = dirsToCreate[i].create(); } else { - future = future.chain((_) { + future = future.then((_) { return dirsToCreate[i].create(); }); } @@ -102,7 +102,7 @@ class _Directory implements Directory { if (future == null) { return new Future.immediate(this); } else { - return future.transform((_) => this); + return future.then((_) => this); } }); } @@ -110,10 +110,10 @@ class _Directory implements Directory { Future create({recursive: false}) { if (recursive) return createRecursively(); _ensureDirectoryService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = CREATE_REQUEST; request[1] = _path; - return _directoryService.call(request).transform((response) { + return _directoryService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionOrErrorFromResponse(response, "Creation failed"); } @@ -149,10 +149,10 @@ class _Directory implements Directory { Future createTemp() { _ensureDirectoryService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = CREATE_TEMP_REQUEST; request[1] = _path; - return _directoryService.call(request).transform((response) { + return _directoryService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionOrErrorFromResponse(response, "Creation of temporary directory failed"); @@ -179,11 +179,11 @@ class _Directory implements Directory { Future delete({recursive: false}) { _ensureDirectoryService(); - List request = new List(3); + List request = new List.fixedLength(3); request[0] = DELETE_REQUEST; request[1] = _path; request[2] = recursive; - return _directoryService.call(request).transform((response) { + return _directoryService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionOrErrorFromResponse(response, "Deletion failed"); } @@ -203,11 +203,11 @@ class _Directory implements Directory { Future rename(String newPath) { _ensureDirectoryService(); - List request = new List(3); + List request = new List.fixedLength(3); request[0] = RENAME_REQUEST; request[1] = _path; request[2] = newPath; - return _directoryService.call(request).transform((response) { + return _directoryService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionOrErrorFromResponse(response, "Rename failed"); } @@ -281,7 +281,7 @@ class _DirectoryLister implements DirectoryLister { final int RESPONSE_COMPLETE = 1; final int RESPONSE_ERROR = 2; - List request = new List(3); + List request = new List.fixedLength(3); request[0] = _Directory.LIST_REQUEST; request[1] = path; request[2] = recursive; diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart index a6344006056..c1d8dc336f2 100644 --- a/sdk/lib/io/file_impl.dart +++ b/sdk/lib/io/file_impl.dart @@ -11,11 +11,10 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { _filePosition = 0 { var file = new File(name); var future = file.open(FileMode.READ); - future.handleException((e) { - _reportError(e); - return true; - }); - future.then(_setupOpenedFile); + future.then(_setupOpenedFile) + .catchError((e) { + _reportError(e.error); + }); } _FileInputStream.fromStdio(int fd) @@ -35,14 +34,14 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { return; } var futureOpen = _openedFile.length(); - futureOpen.then((len) { - _fileLength = len; - _fillBuffer(); - }); - futureOpen.handleException((e) { - _reportError(e); - return true; - }); + futureOpen + .then((len) { + _fileLength = len; + _fillBuffer(); + }) + .catchError((e) { + _reportError(e.error); + }); } void _closeFile() { @@ -82,11 +81,9 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { _closeFile(); } _checkScheduleCallbacks(); - }); - future.handleException((e) { + }).catchError((e) { _activeFillBufferCall = false; - _reportError(e); - return true; + _reportError(e.error); }); } @@ -162,10 +159,8 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { openFuture.then((openedFile) { _file = openedFile; _processPendingOperations(); - }); - openFuture.handleException((e) { - _reportError(e); - return true; + }).catchError((e) { + _reportError(e.error); }); } @@ -267,11 +262,9 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { _onNoPendingWrites != null) { _onNoPendingWrites(); } - }); - writeListFuture.handleException((e) { + }).catchError((e) { outstandingWrites--; - _reportError(e); - return true; + _reportError(e.error); }); } @@ -363,10 +356,10 @@ class _File extends _FileBase implements File { Future exists() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _EXISTS_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot open file '$_name'"); } @@ -384,10 +377,10 @@ class _File extends _FileBase implements File { Future create() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _CREATE_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot create file '$_name'"); } @@ -404,10 +397,10 @@ class _File extends _FileBase implements File { Future delete() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _DELETE_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot delete file '$_name'"); } @@ -424,10 +417,10 @@ class _File extends _FileBase implements File { Future directory() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _DIRECTORY_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot retrieve directory for " @@ -452,15 +445,15 @@ class _File extends _FileBase implements File { mode != FileMode.WRITE && mode != FileMode.APPEND) { new Timer(0, (t) { - completer.completeException(new ArgumentError()); + completer.completeError(new ArgumentError()); }); return completer.future; } - List request = new List(3); + List request = new List.fixedLength(3); request[0] = _OPEN_REQUEST; request[1] = _name; request[2] = mode._mode; // Direct int value for serialization. - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot open file '$_name'"); } @@ -470,10 +463,10 @@ class _File extends _FileBase implements File { Future length() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _LENGTH_FROM_NAME_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot retrieve length of " @@ -494,10 +487,10 @@ class _File extends _FileBase implements File { Future lastModified() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _LAST_MODIFIED_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot retrieve modification time " @@ -541,10 +534,10 @@ class _File extends _FileBase implements File { Future fullPath() { _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _FULL_PATH_REQUEST; request[1] = _name; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "Cannot retrieve full path" @@ -589,7 +582,9 @@ class _File extends _FileBase implements File { var chunk = stream.read(); chunks.add(chunk); }; - stream.onError = completer.completeException; + stream.onError = (e) { + completer.completeError(e); + }; return completer.future; } @@ -607,7 +602,7 @@ class _File extends _FileBase implements File { Future readAsString([Encoding encoding = Encoding.UTF_8]) { _ensureFileService(); - return readAsBytes().transform((bytes) { + return readAsBytes().then((bytes) { if (bytes.length == 0) return ""; var decoder = _StringDecoders.decoder(encoding); decoder.write(bytes); @@ -642,7 +637,7 @@ class _File extends _FileBase implements File { Future> readAsLines([Encoding encoding = Encoding.UTF_8]) { _ensureFileService(); Completer> completer = new Completer>(); - return readAsBytes().transform((bytes) { + return readAsBytes().then((bytes) { var decoder = _StringDecoders.decoder(encoding); decoder.write(bytes); return _getDecodedLines(decoder); @@ -731,13 +726,13 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); _ensureFileService(); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _CLOSE_REQUEST; request[1] = _id; // Set the id_ to 0 (NULL) to ensure the no more async requests // can be issued for this file. _id = 0; - return _fileService.call(request).transform((result) { + return _fileService.call(request).then((result) { if (result != -1) { _id = result; return this; @@ -762,10 +757,10 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { _ensureFileService(); Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _READ_BYTE_REQUEST; request[1] = _id; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "readByte failed for file '$_name'"); @@ -803,7 +798,7 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { request[0] = _READ_REQUEST; request[1] = _id; request[2] = bytes; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "read failed for file '$_name'"); @@ -830,17 +825,17 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { // handlers without getting exceptions when registering the // then handler. new Timer(0, (t) { - completer.completeException(new FileIOException( + completer.completeError(new FileIOException( "Invalid arguments to readList for file '$_name'")); }); return completer.future; }; if (closed) return _completeWithClosedException(completer); - List request = new List(3); + List request = new List.fixedLength(3); request[0] = _READ_LIST_REQUEST; request[1] = _id; request[2] = bytes; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "readList failed for file '$_name'"); @@ -886,17 +881,17 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { // handlers without getting exceptions when registering the // then handler. new Timer(0, (t) { - completer.completeException(new FileIOException( + completer.completeError(new FileIOException( "Invalid argument to writeByte for file '$_name'")); }); return completer.future; } if (closed) return _completeWithClosedException(completer); - List request = new List(3); + List request = new List.fixedLength(3); request[0] = _WRITE_BYTE_REQUEST; request[1] = _id; request[2] = value; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "writeByte failed for file '$_name'"); @@ -929,7 +924,7 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { // handlers without getting exceptions when registering the // then handler. new Timer(0, (t) { - completer.completeException(new FileIOException( + completer.completeError(new FileIOException( "Invalid arguments to writeList for file '$_name'")); }); return completer.future; @@ -943,17 +938,17 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { // Complete asynchronously so the user has a chance to setup // handlers without getting exceptions when registering the // then handler. - new Timer(0, (t) => completer.completeException(e)); + new Timer(0, (t) => completer.completeError(e)); return completer.future; } - List request = new List(5); + List request = new List.fixedLength(5); request[0] = _WRITE_LIST_REQUEST; request[1] = _id; request[2] = result.buffer; request[3] = result.offset; request[4] = bytes; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "writeList failed for file '$_name'"); @@ -987,7 +982,7 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { if (encoding is! Encoding) { var completer = new Completer(); new Timer(0, (t) { - completer.completeException(new FileIOException( + completer.completeError(new FileIOException( "Invalid encoding in writeString: $encoding")); }); return completer.future; @@ -1009,10 +1004,10 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { _ensureFileService(); Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _POSITION_REQUEST; request[1] = _id; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "position failed for file '$_name'"); @@ -1036,11 +1031,11 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { _ensureFileService(); Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); - List request = new List(3); + List request = new List.fixedLength(3); request[0] = _SET_POSITION_REQUEST; request[1] = _id; request[2] = position; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "setPosition failed for file '$_name'"); @@ -1063,11 +1058,11 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { _ensureFileService(); Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); - List request = new List(3); + List request = new List.fixedLength(3); request[0] = _TRUNCATE_REQUEST; request[1] = _id; request[2] = length; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "truncate failed for file '$_name'"); @@ -1090,10 +1085,10 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { _ensureFileService(); Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _LENGTH_REQUEST; request[1] = _id; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "length failed for file '$_name'"); @@ -1117,10 +1112,10 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { _ensureFileService(); Completer completer = new Completer(); if (closed) return _completeWithClosedException(completer); - List request = new List(2); + List request = new List.fixedLength(2); request[0] = _FLUSH_REQUEST; request[1] = _id; - return _fileService.call(request).transform((response) { + return _fileService.call(request).then((response) { if (_isErrorResponse(response)) { throw _exceptionFromResponse(response, "flush failed for file '$_name'"); @@ -1157,7 +1152,7 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { Future _completeWithClosedException(Completer completer) { new Timer(0, (t) { - completer.completeException( + completer.completeError( new FileIOException("File closed '$_name'")); }); return completer.future; diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart index beb9b8913a2..eb49406bc4b 100644 --- a/sdk/lib/io/http_headers.dart +++ b/sdk/lib/io/http_headers.dart @@ -188,7 +188,7 @@ class _HttpHeaders implements HttpHeaders { if (value is int) { contentLength = value; } else if (value is String) { - contentLength = parseInt(value); + contentLength = int.parse(value); } else { throw new HttpException("Unexpected type for header named $name"); } @@ -237,7 +237,7 @@ class _HttpHeaders implements HttpHeaders { _port = HttpClient.DEFAULT_HTTP_PORT; } else { try { - _port = parseInt(value.substring(pos + 1)); + _port = int.parse(value.substring(pos + 1)); } on FormatException catch (e) { _port = null; } @@ -630,7 +630,7 @@ class _Cookie implements Cookie { if (name == "expires") { expires = _HttpUtils.parseCookieDate(value); } else if (name == "max-age") { - maxAge = parseInt(value); + maxAge = int.parse(value); } else if (name == "domain") { domain = value; } else if (name == "path") { diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart index fb82ba23e31..841a614674a 100644 --- a/sdk/lib/io/http_impl.dart +++ b/sdk/lib/io/http_impl.dart @@ -94,11 +94,11 @@ class _HttpRequestResponseBase { List connection = headers[HttpHeaders.CONNECTION]; if (_protocolVersion == "1.1") { if (connection == null) return true; - return !headers[HttpHeaders.CONNECTION].some( + return !headers[HttpHeaders.CONNECTION].any( (value) => value.toLowerCase() == "close"); } else { if (connection == null) return false; - return headers[HttpHeaders.CONNECTION].some( + return headers[HttpHeaders.CONNECTION].any( (value) => value.toLowerCase() == "keep-alive"); } } @@ -1269,9 +1269,9 @@ class _HttpClientRequest bool _emptyBody = true; } - class _HttpClientResponse - extends _HttpRequestResponseBase implements HttpClientResponse { + extends _HttpRequestResponseBase + implements HttpClientResponse { _HttpClientResponse(_HttpClientConnection connection) : super(connection) { _connection = connection; diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart index 5a726dafee9..69d45056d82 100644 --- a/sdk/lib/io/http_parser.dart +++ b/sdk/lib/io/http_parser.dart @@ -328,7 +328,7 @@ class _HttpParser { case _State.RESPONSE_LINE_ENDING: _expect(byte, _CharCode.LF); _messageType == _MessageType.RESPONSE; - _statusCode = parseInt( + _statusCode = int.parse( new String.fromCharCodes(_method_or_status_code)); if (_statusCode < 100 || _statusCode > 599) { throw new HttpParserException("Invalid response status code"); diff --git a/sdk/lib/io/http_utils.dart b/sdk/lib/io/http_utils.dart index 9e236138c93..927691c825c 100644 --- a/sdk/lib/io/http_utils.dart +++ b/sdk/lib/io/http_utils.dart @@ -207,7 +207,7 @@ class _HttpUtils { String tmp = date.substring(index, pos); index = pos + separator.length; try { - int value = parseInt(tmp); + int value = int.parse(tmp); return value; } on FormatException catch (e) { throw new HttpException("Invalid HTTP date $date"); @@ -300,7 +300,7 @@ class _HttpUtils { int toInt(String s) { int index = 0; for (; index < s.length && isDigit(s[index]); index++); - return parseInt(s.substring(0, index)); + return int.parse(s.substring(0, index)); } var tokens = []; diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart index b976aaeacb1..84ecb53564b 100644 --- a/sdk/lib/io/io.dart +++ b/sdk/lib/io/io.dart @@ -12,6 +12,7 @@ */ library dart.io; +import 'dart:async'; import 'dart:crypto'; import 'dart:isolate'; import 'dart:math'; diff --git a/sdk/lib/io/mime_multipart_parser.dart b/sdk/lib/io/mime_multipart_parser.dart index beb971e28e4..1ae374c2148 100644 --- a/sdk/lib/io/mime_multipart_parser.dart +++ b/sdk/lib/io/mime_multipart_parser.dart @@ -42,7 +42,7 @@ class _MimeMultipartParser { // type parameter, that is without the -- prefix. _MimeMultipartParser(String boundary) { List charCodes = boundary.charCodes; - _boundary = new List(4 + charCodes.length); + _boundary = new List.fixedLength(4 + charCodes.length); // Set-up the matching boundary preceding it with CRLF and two // dashes. _boundary[0] = _CharCode.CR; diff --git a/sdk/lib/io/path_impl.dart b/sdk/lib/io/path_impl.dart index 6f3e892cda0..d2038381d65 100644 --- a/sdk/lib/io/path_impl.dart +++ b/sdk/lib/io/path_impl.dart @@ -134,7 +134,7 @@ class _Path implements Path { } if (segs.last == '') segs.removeLast(); // Path ends with /. // No remaining segments can be ., .., or empty. - return !segs.some((s) => s == '' || s == '.' || s == '..'); + return !segs.any((s) => s == '' || s == '.' || s == '..'); } Path makeCanonical() { diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart index 34e0140a751..4bbb98da584 100644 --- a/sdk/lib/io/process.dart +++ b/sdk/lib/io/process.dart @@ -42,7 +42,7 @@ set exitCode(int status) { * [Process] is used to start new processes using the static * [start] and [run] methods. */ -abstract class Process { +abstract class Process extends StreamSink { /** * Starts a process running the [executable] with the specified * [arguments]. Returns a [:Future:] that completes with a @@ -102,6 +102,10 @@ abstract class Process { */ OutputStream get stdin; + + Stream> get stdoutStream; + Stream> get stderrStream; + /** * Sets an exit handler which gets invoked when the process * terminates. diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart index bcd44f0332a..c660740f0f7 100644 --- a/sdk/lib/io/websocket_impl.dart +++ b/sdk/lib/io/websocket_impl.dart @@ -379,7 +379,7 @@ class _WebSocketConnectionBase { } _socket.onData = () { int available = _socket.available(); - List data = new List(available); + List data = new List.fixedLength(available); int read = _socket.readList(data, 0, available); processor.update(data, 0, read); }; @@ -536,7 +536,7 @@ class _WebSocketConnectionBase { } else if (dataLength > 125) { headerSize += 2; } - List header = new List(headerSize); + List header = new List.fixedLength(headerSize); int index = 0; // Set FIN and opcode. header[index++] = 0x80 | opcode; @@ -601,8 +601,8 @@ class _WebSocketHandler implements WebSocketHandler { response.headers.add(HttpHeaders.UPGRADE, "websocket"); String key = request.headers.value("Sec-WebSocket-Key"); SHA1 sha1 = new SHA1(); - sha1.update("$key$_webSocketGUID".charCodes); - String accept = _Base64._encode(sha1.digest()); + sha1.add("$key$_webSocketGUID".charCodes); + String accept = _Base64._encode(sha1.close()); response.headers.add("Sec-WebSocket-Accept", accept); response.contentLength = 0; @@ -722,7 +722,7 @@ class _WebSocketClientConnection } // Generate 16 random bytes. Use the last four bytes for the hash code. - List nonce = new List(16); + List nonce = new List.fixedLength(16); for (int i = 0; i < 4; i++) { int r = random.nextInt(0x100000000); intToBigEndianBytes(r, nonce, i * 4); @@ -749,8 +749,8 @@ class _WebSocketClientConnection return false; } SHA1 sha1 = new SHA1(); - sha1.update("$_nonce$_webSocketGUID".charCodes); - List expectedAccept = sha1.digest(); + sha1.add("$_nonce$_webSocketGUID".charCodes); + List expectedAccept = sha1.close(); List receivedAccept = _Base64._decode(accept); if (expectedAccept.length != receivedAccept.length) return false; for (int i = 0; i < expectedAccept.length; i++) { diff --git a/sdk/lib/isolate/base.dart b/sdk/lib/isolate/base.dart index 93f8efee0bd..c6c36e016f6 100644 --- a/sdk/lib/isolate/base.dart +++ b/sdk/lib/isolate/base.dart @@ -16,7 +16,7 @@ class IsolateSpawnException implements Exception { * the first communication between isolates (see [spawnFunction] and * [spawnUri]). */ -external ReceivePort get port; +ReceivePort get port => _Isolate.port; /** * Creates and spawns an isolate that shares the same code as the current @@ -33,9 +33,10 @@ external ReceivePort get port; * * See comments at the top of this library for more details. */ -// Note this feature is not yet available in the dartvm. -external SendPort spawnFunction(void topLevelFunction(), - [bool UnhandledExceptionCallback(IsolateUnhandledException e)]); +SendPort spawnFunction(void topLevelFunction(), + [bool UnhandledExceptionCallback(IsolateUnhandledException e)]) + => _Isolate.spawnFunction(topLevelFunction, UnhandledExceptionCallback); + /** * Creates and spawns an isolate whose code is available at [uri]. Like with * [spawnFunction], the child isolate will have a default [ReceivePort], and a @@ -43,7 +44,7 @@ external SendPort spawnFunction(void topLevelFunction(), * * See comments at the top of this library for more details. */ -external SendPort spawnUri(String uri); +SendPort spawnUri(String uri) => _Isolate.spawnUri(uri); /** * [SendPort]s are created from [ReceivePort]s. Any message sent through @@ -145,6 +146,16 @@ abstract class SendPortSync { } +// The VM doesn't support accessing external globals in the same library. We +// therefore create this wrapper class. +// TODO(6997): Don't go through static class for external variables. +abstract class _Isolate { + external static ReceivePort get port; + external static SendPort spawnFunction(void topLevelFunction(), + [bool UnhandledExceptionCallback(IsolateUnhandledException e)]); + external static SendPort spawnUri(String uri); +} + /** * Wraps unhandled exceptions thrown during isolate execution. It is * used to show both the error message and the stack trace for unhandled diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart index ab4c71df338..947cc1446dd 100644 --- a/sdk/lib/isolate/isolate.dart +++ b/sdk/lib/isolate/isolate.dart @@ -4,5 +4,8 @@ library dart.isolate; +import "dart:async"; + part "base.dart"; -part "timer.dart"; +part "isolate_stream.dart"; +part "mangler.dart"; diff --git a/sdk/lib/isolate/isolate_sources.gypi b/sdk/lib/isolate/isolate_sources.gypi index 53d416419fe..4481e935da7 100644 --- a/sdk/lib/isolate/isolate_sources.gypi +++ b/sdk/lib/isolate/isolate_sources.gypi @@ -5,6 +5,7 @@ { 'sources': [ 'base.dart', - 'timer.dart' + 'isolate_stream.dart', + 'mangler.dart', ], } diff --git a/sdk/lib/isolate/isolate_stream.dart b/sdk/lib/isolate/isolate_stream.dart new file mode 100644 index 00000000000..26410154754 --- /dev/null +++ b/sdk/lib/isolate/isolate_stream.dart @@ -0,0 +1,215 @@ +// Copyright (c) 2012, 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. + +part of dart.isolate; + +/** + * The initial [IsolateStream] available by default for this isolate. This + * [IsolateStream] is created automatically and it is commonly used to establish + * the first communication between isolates (see [streamSpawnFunction] and + * [streamSpawnUri]). + */ +final IsolateStream stream = new IsolateStream._fromOriginalReceivePort(port); + +/** + * A [MessageBox] creates an [IsolateStream], [stream], and an [IsolateSink], + * [sink]. + * + * Any message that is written into the [sink] (independent of the isolate) is + * sent to the [stream] where its subscribers can react to the messages. + */ +class MessageBox { + final IsolateStream stream; + final IsolateSink sink; + + MessageBox.oneShot() : this._oneShot(new ReceivePort()); + MessageBox._oneShot(ReceivePort receivePort) + : stream = new IsolateStream._fromOriginalReceivePortOneShot(receivePort), + sink = new IsolateSink._fromPort(receivePort.toSendPort()); + + MessageBox() : this._(new ReceivePort()); + MessageBox._(ReceivePort receivePort) + : stream = new IsolateStream._fromOriginalReceivePort(receivePort), + sink = new IsolateSink._fromPort(receivePort.toSendPort()); +} + +// Used for mangling. +const int _ISOLATE_STREAM_TOKEN = 132421119; + +class _CloseToken { + /// This token is sent from [IsolateSink]s to [IsolateStream]s to ask them to + /// close themselves. + const _CloseToken(); +} + +/** + * [IsolateStream]s, together with [IsolateSink]s, are the only means of + * communication between isolates. Each IsolateStream has a corresponding + * [IsolateSink]. Any message written into that sink will be delivered to + * the stream and then dispatched to the stream's subscribers. + */ +class IsolateStream extends Stream { + bool _isClosed = false; + final ReceivePort _port; + StreamController _controller = new StreamController(); + + IsolateStream._fromOriginalReceivePort(this._port) { + _port.receive((message, replyTo) { + assert(replyTo == null); + _add(message); + }); + } + + IsolateStream._fromOriginalReceivePortOneShot(this._port) { + _port.receive((message, replyTo) { + assert(replyTo == null); + _add(message); + close(); + }); + } + + void _add(var message) { + message = _unmangleMessage(message); + if (identical(message, const _CloseToken())) { + close(); + } else { + _controller.sink.add(message); + } + } + + /** + * Close the stream from the receiving end. + * + * Closing an already closed port has no effect. + */ + void close() { + if (!_isClosed) { + _isClosed = true; + _port.close(); + _controller.close(); + } + } + + StreamSubscription listen(void onData(T event), + { void onError(AsyncError error), + void onDone(), + bool unsubscribeOnError}) { + return _controller.listen(onData, + onError: onError, + onDone: onDone, + unsubscribeOnError: unsubscribeOnError); + } + + dynamic _unmangleMessage(var message) { + _IsolateDecoder decoder = new _IsolateDecoder( + _ISOLATE_STREAM_TOKEN, + (data) { + if (data is! List) return data; + if (data.length == 2 && data[0] == "Sink" && data[1] is SendPort) { + return new IsolateSink._fromPort(data[1]); + } + if (data.length == 1 && data[0] == "Close") { + return const _CloseToken(); + } + return data; + }); + return decoder.decode(message); + } +} + +/** + * [IsolateSink]s represent the feed for [IsolateStream]s. Any message written + * to [this] is delivered to its respective [IsolateStream]. [IsolateSink]s are + * created by [MessageBox]es. + * + * [IsolateSink]s can be transmitted to other isolates. + */ +class IsolateSink extends StreamSink { + bool _isClosed = false; + final SendPort _port; + IsolateSink._fromPort(this._port); + + /** + * Sends an asynchronous [message] to the linked [IsolateStream]. The message + * is copied to the receiving isolate. + * + * The content of [message] can be: primitive values (null, num, bool, double, + * String), instances of [IsolateSink]s, and lists and maps whose elements are + * any of these. List and maps are also allowed to be cyclic. + * + * In the special circumstances when two isolates share the same code and are + * running in the same process (e.g. isolates created via [spawnFunction]), it + * is also possible to send object instances (which would be copied in the + * process). This is currently only supported by the dartvm. For now, the + * dart2js compiler only supports the restricted messages described above. + */ + void add(dynamic message) { + var mangled = _mangleMessage(message); + _port.send(mangled); + } + + void signalError(AsyncError errorEvent) { + throw new UnimplementedError("signalError on isolate streams"); + } + + dynamic _mangleMessage(var message) { + _IsolateEncoder encoder = new _IsolateEncoder( + _ISOLATE_STREAM_TOKEN, + (data) { + if (data is IsolateSink) return ["Sink", data._port]; + if (identical(data, const _CloseToken())) return ["Close"]; + return data; + }); + return encoder.encode(message); + } + + void close() { + if (_isClosed) throw new StateError("Sending on closed stream"); + add(const _CloseToken()); + _isClosed = true; + } + + /** + * Tests whether [other] is an [IsolateSink] feeding into the same + * [IsolateStream] as this one. + */ + bool operator==(var other) { + return other is IsolateSink && _port == other._port; + } + + int get hashCode => _port.hashCode + 499; +} + + +/** + * Creates and spawns an isolate that shares the same code as the current + * isolate, but that starts from [topLevelFunction]. The [topLevelFunction] + * argument must be a static top-level function or a static method that takes no + * arguments. + * + * When any isolate starts (even the main script of the application), a default + * [IsolateStream] is created for it. This sink is available from the top-level + * getter [stream] defined in this library. + * + * [spawnFunction] returns an [IsolateSink] feeding into the child isolate's + * default stream. + * + * See comments at the top of this library for more details. + */ +IsolateSink streamSpawnFunction(void topLevelFunction()) { + SendPort sendPort = spawnFunction(topLevelFunction); + return new IsolateSink._fromPort(sendPort); +} + +/** + * Creates and spawns an isolate whose code is available at [uri]. Like with + * [streamSpawnFunction], the child isolate will have a default [IsolateStream], + * and a this function returns an [IsolateSink] feeding into it. + * + * See comments at the top of this library for more details. + */ +IsolateSink streamSpawnUri(String uri) { + SendPort sendPort = spawnUri(uri); + return new IsolateSink._fromPort(sendPort); +} diff --git a/sdk/lib/isolate/mangler.dart b/sdk/lib/isolate/mangler.dart new file mode 100644 index 00000000000..a0e16721a4d --- /dev/null +++ b/sdk/lib/isolate/mangler.dart @@ -0,0 +1,270 @@ +// Copyright (c) 2012, 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. + +part of dart.isolate; + +class _IsolateEncoder { + final manglingToken; + // TODO(floitsch): switch to identity set. + final Map _encoded = new Map(); + final Map _visiting = new Map(); + final Function _mangle; + static const int _REFERENCE = 0; + static const int _DECLARATION = 1; + static const int _ESCAPED = 2; + static const int _MANGLED = 3; + + _IsolateEncoder(this.manglingToken, mangle(data)) + : this._mangle = mangle; + + encode(var data) { + if (data is num || data is String || data is bool || data == null) { + return data; + } + + if (_encoded.containsKey(data)) return _encoded[data]; + if (_visiting.containsKey(data)) { + // Self reference. + var selfReference = _visiting[data]; + if (selfReference == data) { + // Nobody used the self-reference yet. + selfReference = _createReference(); + _visiting[data] = selfReference; + } + return selfReference; + } + _visiting[data] = data; + + var result; + + if (data is List) { + bool hasBeenDuplicated = false; + result = data; + for (int i = 0; i < data.length; i++) { + var mangled = encode(data[i]); + if (mangled != data[i] && !hasBeenDuplicated) { + result = new List.fixedLength(data.length); + for (int j = 0; j < i; j++) { + result[j] = data[j]; + } + hasBeenDuplicated = true; + } + if (hasBeenDuplicated) { + result[i] = mangled; + } + } + result = _escapeIfNecessary(result); + } else if (data is Set) { + // TODO(floitsch): should we accept sets? + bool needsCopy = false; + for (var entry in data) { + var encoded = encode(entry); + if (encoded != entry) { + needsCopy = true; + break; + } + } + result = data; + if (needsCopy) { + result = new Set(); + data.forEach((entry) { + result.add(encode(entry)); + }); + } + } else if (data is Map) { + bool needsCopy = false; + data.forEach((key, value) { + var encodedKey = encode(key); + var encodedValue = encode(value); + if (encodedKey != key) needsCopy = true; + if (encodedValue != value) needsCopy = true; + }); + result = data; + if (needsCopy) { + result = new Map(); + data.forEach((key, value) { + result[encode(key)] = encode(value); + }); + } + } else { + // We don't handle self-references for user data. + // TODO(floitsch): we could keep the reference and throw when we see it + // again. However now the user has at least the possibility to do + // cyclic data-structures. + _visiting.remove(data); + result = _mangle(data); + if (result != data) { + result = _wrapMangled(encode(result)); + } + } + + var selfReference = _visiting[data]; + if (selfReference != null && selfReference != data) { + // A self-reference has been used. + result = _declareReference(selfReference, result); + } + _encoded[data] = result; + + _visiting.remove(data); + return result; + } + + _createReference() => [manglingToken, _REFERENCE]; + _declareReference(reference, data) { + return [manglingToken, _DECLARATION, reference, data]; + } + + _wrapMangled(data) => [manglingToken, _MANGLED, data]; + _escapeIfNecessary(List list) { + if (!list.isEmpty && list[0] == manglingToken) { + return [manglingToken, _ESCAPED, list]; + } else { + return list; + } + } +} + +class _IsolateDecoder { + final manglingToken; + final Map _decoded = new Map(); + final Function _unmangle; + static const int _REFERENCE = _IsolateEncoder._REFERENCE; + static const int _DECLARATION = _IsolateEncoder._DECLARATION; + static const int _ESCAPED = _IsolateEncoder._ESCAPED; + static const int _MANGLED = _IsolateEncoder._MANGLED; + + _IsolateDecoder(this.manglingToken, unmangle(data)) + : this._unmangle = unmangle; + + decode(var data) { + if (data is num || data is String || data is bool || data == null) { + return data; + } + + if (_decoded.containsKey(data)) return _decoded[data]; + + if (_isDeclaration(data)) { + var reference = _extractReference(data); + var declared = _extractDeclared(data); + return _decodeObject(declared, reference); + } else { + return _decodeObject(data, null); + } + } + + _decodeObject(data, reference) { + if (_decoded.containsKey(data)) { + assert(reference == null); + return _decoded[data]; + } + + // If the data was a reference then we would have found it in the _decoded + // map. + assert(!_isReference(data)); + + var result; + if (_isMangled(data)) { + assert(reference == null); + List mangled = _extractMangled(data); + var decoded = decode(mangled); + result = _unmangle(decoded); + } else if (data is List) { + if (_isEscaped(data)) data = _extractEscaped(data); + assert(!_isMarked(data)); + result = data; + bool hasBeenDuplicated = false; + List duplicate() { + assert(!hasBeenDuplicated); + result = new List(); + result.length = data.length; + if (reference != null) _decoded[reference] = result; + hasBeenDuplicated = true; + } + + if (reference != null) duplicate(); + for (int i = 0; i < data.length; i++) { + var decoded = decode(data[i]); + if (decoded != data[i] && !hasBeenDuplicated) { + duplicate(); + for (int j = 0; j < i; j++) { + result[j] = data[j]; + } + } + if (hasBeenDuplicated) { + result[i] = decoded; + } + } + } else if (data is Set) { + bool needsCopy = reference != null; + if (!needsCopy) { + for (var entry in data) { + var decoded = decode(entry); + if (decoded != entry) { + needsCopy = true; + break; + } + } + } + result = data; + if (needsCopy) { + result = new Set(); + if (reference != null) _decoded[reference] = result; + for (var entry in data) { + result.add(decode(entry)); + } + } + } else if (data is Map) { + bool needsCopy = reference != null; + if (!needsCopy) { + data.forEach((key, value) { + var decodedKey = decode(key); + var decodedValue = decode(value); + if (decodedKey != key) needsCopy = true; + if (decodedValue != value) needsCopy = true; + }); + } + result = data; + if (needsCopy) { + result = new Map(); + if (reference != null) _decoded[reference] = result; + data.forEach((key, value) { + result[decode(key)] = decode(value); + }); + } + } else { + result = data; + } + _decoded[data] = result; + return result; + } + + _isMarked(data) { + if (data is List && !data.isEmpty && data[0] == manglingToken) { + assert(data.length > 1); + return true; + } + return false; + } + _isReference(data) => _isMarked(data) && data[1] == _REFERENCE; + _isDeclaration(data) => _isMarked(data) && data[1] == _DECLARATION; + _isMangled(data) => _isMarked(data) && data[1] == _MANGLED; + _isEscaped(data) => _isMarked(data) && data[1] == _ESCAPED; + + _extractReference(declaration) { + assert(_isDeclaration(declaration)); + return declaration[2]; + } + _extractDeclared(declaration) { + assert(_isDeclaration(declaration)); + return declaration[3]; + } + _extractMangled(wrappedMangled) { + assert(_isMangled(wrappedMangled)); + return wrappedMangled[2]; + } + _extractEscaped(data) { + assert(_isEscaped(data)); + return data[2]; + } +} diff --git a/sdk/lib/json/json.dart b/sdk/lib/json/json.dart index 5ba8a74c62a..5de1b0e1a13 100644 --- a/sdk/lib/json/json.dart +++ b/sdk/lib/json/json.dart @@ -4,8 +4,6 @@ library dart.json; -import 'dart:math'; - // JSON parsing and serialization. /** @@ -13,13 +11,12 @@ import 'dart:math'; * * The [unsupportedObject] field holds that object that failed to be serialized. * - * If an isn't directly serializable, the serializer calls the 'toJson' method - * on the object. If that call fails, the error will be stored in the [cause] - * field. If the call returns an object that isn't directly serializable, - * the [cause] will be null. + * If an object isn't directly serializable, the serializer calls the 'toJson' + * method on the object. If that call fails, the error will be stored in the + * [cause] field. If the call returns an object that isn't directly + * serializable, the [cause] will be null. */ -class JsonUnsupportedObjectError { - // TODO: proper base class. +class JsonUnsupportedObjectError implements Error { /** The object that could not be serialized. */ final unsupportedObject; /** The exception thrown by object's [:toJson:] method, if any. */ @@ -38,406 +35,606 @@ class JsonUnsupportedObjectError { /** - * Utility class to parse JSON and serialize objects to JSON. + * Parses [json] and build the corresponding parsed JSON value. + * + * Parsed JSON values are of the types [num], [String], [bool], [Null], + * [List]s of parsed JSON values or [Map]s from [String] to parsed + * JSON values. + * + * Throws [FormatException] if the input is not valid JSON text. */ -class JSON { - /** - * Parses [json] and build the corresponding parsed JSON value. - * - * Parsed JSON values are of the types [num], [String], [bool], [Null], - * [List]s of parsed JSON values or [Map]s from [String] to parsed - * JSON values. - * - * Throws [JSONParseException] if the input is not valid JSON text. - */ - static parse(String json) { - return _JsonParser.parse(json); +parse(String json, [reviver(var key, var value)]) { + BuildJsonListener listener; + if (reviver == null) { + listener = new BuildJsonListener(); + } else { + listener = new ReviverJsonListener(reviver); } + new JsonParser(json, listener).parse(); + return listener.result; +} - /** - * Serializes [object] into a JSON string. - * - * Directly serializable types are [num], [String], [bool], [Null], [List] - * and [Map]. - * For [List], the elements must all be serializable. - * For [Map], the keys must be [String] and the values must be serializable. - * If a value is any other type is attempted serialized, a "toJson()" method - * is invoked on the object and the result, which must be a directly - * serializable type, is serialized instead of the original value. - * If the object does not support this method, throws, or returns a - * value that is not directly serializable, a [JsonUnsupportedObjectError] - * exception is thrown. If the call throws (including the case where there - * is no nullary "toJson" method, the error is caught and stored in the - * [JsonUnsupportedObjectError]'s [:cause:] field. - * - * Objects should not change during serialization. - * If an object is serialized more than once, [stringify] is allowed to cache - * the JSON text for it. I.e., if an object changes after it is first - * serialized, the new values may or may not be reflected in the result. - */ - static String stringify(Object object) { - return _JsonStringifier.stringify(object); - } +/** + * Serializes [object] into a JSON string. + * + * Directly serializable types are [num], [String], [bool], [Null], [List] + * and [Map]. + * For [List], the elements must all be serializable. + * For [Map], the keys must be [String] and the values must be serializable. + * If a value is any other type is attempted serialized, a "toJson()" method + * is invoked on the object and the result, which must be a directly + * serializable type, is serialized instead of the original value. + * If the object does not support this method, throws, or returns a + * value that is not directly serializable, a [JsonUnsupportedObjectError] + * exception is thrown. If the call throws (including the case where there + * is no nullary "toJson" method, the error is caught and stored in the + * [JsonUnsupportedObjectError]'s [:cause:] field. + *Json + * Objects should not change during serialization. + * If an object is serialized more than once, [stringify] is allowed to cache + * the JSON text for it. I.e., if an object changes after it is first + * serialized, the new values may or may not be reflected in the result. + */ +String stringify(Object object) { + return _JsonStringifier.stringify(object); +} - /** - * Serializes [object] into [output] stream. - * - * Performs the same operations as [stringify] but outputs the resulting - * string to an existing [StringBuffer] instead of creating a new [String]. - * - * If serialization fails by throwing, some data might have been added to - * [output], but it won't contain valid JSON text. - */ - static void printOn(Object object, StringBuffer output) { - return _JsonStringifier.printOn(object, output); - } +/** + * Serializes [object] into [output] stream. + * + * Performs the same operations as [stringify] but outputs the resulting + * string to an existing [StringBuffer] instead of creating a new [String]. + * + * If serialization fails by throwing, some data might have been added to + * [output], but it won't contain valid JSON text. + */ +void printOn(Object object, StringBuffer output) { + return _JsonStringifier.printOn(object, output); } //// Implementation /////////////////////////////////////////////////////////// -// TODO(ajohnsen): Introduce when we have a common exception interface for json. -class JSONParseException { - JSONParseException(int position, String message) : - position = position, - message = 'JSONParseException: $message, at offset $position'; +// Simple API for JSON parsing. - String toString() => message; - - final String message; - final int position; +abstract class JsonListener { + void handleString(String value) {} + void handleNumber(num value) {} + void handleBool(bool value) {} + void handleNull() {} + void beginObject() {} + void propertyName() {} + void propertyValue() {} + void endObject() {} + void beginArray() {} + void arrayElement() {} + void endArray() {} + /** Called on failure to parse [source]. */ + void fail(String source, int position, String message) {} } -class _JsonParser { - static const int BACKSPACE = 8; - static const int TAB = 9; - static const int NEW_LINE = 10; - static const int FORM_FEED = 12; - static const int CARRIAGE_RETURN = 13; - static const int SPACE = 32; - static const int QUOTE = 34; - static const int PLUS = 43; - static const int COMMA = 44; - static const int MINUS = 45; - static const int DOT = 46; - static const int SLASH = 47; - static const int CHAR_0 = 48; - static const int CHAR_1 = 49; - static const int CHAR_2 = 50; - static const int CHAR_3 = 51; - static const int CHAR_4 = 52; - static const int CHAR_5 = 53; - static const int CHAR_6 = 54; - static const int CHAR_7 = 55; - static const int CHAR_8 = 56; - static const int CHAR_9 = 57; - static const int COLON = 58; - static const int CHAR_CAPITAL_E = 69; - static const int LBRACKET = 91; - static const int BACKSLASH = 92; - static const int RBRACKET = 93; - static const int CHAR_B = 98; - static const int CHAR_E = 101; - static const int CHAR_F = 102; - static const int CHAR_N = 110; - static const int CHAR_R = 114; - static const int CHAR_T = 116; - static const int CHAR_U = 117; - static const int LBRACE = 123; - static const int RBRACE = 125; +/** + * A [JsonListener] that builds data objects from the parser events. + * + * This is a simple stack-based object builder. It keeps the most recently + * seen value in a variable, and uses it depending on the following event. + */ +class BuildJsonListener extends JsonListener { + /** + * Stack used to handle nested containers. + * + * The current container is pushed on the stack when a new one is + * started. If the container is a [Map], there is also a current [key] + * which is also stored on the stack. + */ + List stack = []; + /** The current [Map] or [List] being built. */ + var currentContainer; + /** The most recently read property key. */ + String key; + /** The most recently read value. */ + var value; - static const int STRING_LITERAL = QUOTE; - static const int NUMBER_LITERAL = MINUS; - static const int NULL_LITERAL = CHAR_N; - static const int FALSE_LITERAL = CHAR_F; - static const int TRUE_LITERAL = CHAR_T; - - static const int WHITESPACE = SPACE; - - static const int LAST_ASCII = RBRACE; - - static const String NULL_STRING = "null"; - static const String TRUE_STRING = "true"; - static const String FALSE_STRING = "false"; - - static List tokens; - - final String json; - final int length; - int position = 0; - - static parse(String json) { - return new _JsonParser(json).parseToplevel(); + /** Pushes the currently active container (and key, if a [Map]). */ + void pushContainer() { + if (currentContainer is Map) stack.add(key); + stack.add(currentContainer); } - _JsonParser(String json) - : json = json, - length = json.length { - if (tokens != null) return; - - // Use a list as jump-table. It is faster than switch and if. - tokens = new List(LAST_ASCII + 1); - tokens[TAB] = WHITESPACE; - tokens[NEW_LINE] = WHITESPACE; - tokens[CARRIAGE_RETURN] = WHITESPACE; - tokens[SPACE] = WHITESPACE; - tokens[CHAR_0] = NUMBER_LITERAL; - tokens[CHAR_1] = NUMBER_LITERAL; - tokens[CHAR_2] = NUMBER_LITERAL; - tokens[CHAR_3] = NUMBER_LITERAL; - tokens[CHAR_4] = NUMBER_LITERAL; - tokens[CHAR_5] = NUMBER_LITERAL; - tokens[CHAR_6] = NUMBER_LITERAL; - tokens[CHAR_7] = NUMBER_LITERAL; - tokens[CHAR_8] = NUMBER_LITERAL; - tokens[CHAR_9] = NUMBER_LITERAL; - tokens[MINUS] = NUMBER_LITERAL; - tokens[LBRACE] = LBRACE; - tokens[RBRACE] = RBRACE; - tokens[LBRACKET] = LBRACKET; - tokens[RBRACKET] = RBRACKET; - tokens[QUOTE] = STRING_LITERAL; - tokens[COLON] = COLON; - tokens[COMMA] = COMMA; - tokens[CHAR_N] = NULL_LITERAL; - tokens[CHAR_T] = TRUE_LITERAL; - tokens[CHAR_F] = FALSE_LITERAL; + /** Pops the top container from the [stack], including a key if applicable. */ + void popContainer() { + value = currentContainer; + currentContainer = stack.removeLast(); + if (currentContainer is Map) key = stack.removeLast(); } - parseToplevel() { - final result = parseValue(); - if (token() != null) { - error('Junk at the end of JSON input'); - } - return result; + void handleString(String value) { this.value = value; } + void handleNumber(num value) { this.value = value; } + void handleBool(bool value) { this.value = value; } + void handleNull() { this.value = value; } + + void beginObject() { + pushContainer(); + currentContainer = {}; } - parseValue() { - final int token = token(); - if (token == null) { - error('Nothing to parse'); - } - switch (token) { - case STRING_LITERAL: return parseString(); - case NUMBER_LITERAL: return parseNumber(); - case NULL_LITERAL: return expectKeyword(NULL_STRING, null); - case FALSE_LITERAL: return expectKeyword(FALSE_STRING, false); - case TRUE_LITERAL: return expectKeyword(TRUE_STRING, true); - case LBRACE: return parseObject(); - case LBRACKET: return parseList(); - - default: - error('Unexpected token'); - } + void propertyName() { + key = value; + value = null; } - Object expectKeyword(String word, Object value) { - for (int i = 0; i < word.length; i++) { - // Implicit end check in char(). - if (char() != word.charCodeAt(i)) error("Expected keyword '$word'"); - position++; - } + void propertyValue() { + Map map = currentContainer; + map[key] = value; + key = value = null; + } + + void endObject() { + popContainer(); + } + + void beginArray() { + pushContainer(); + currentContainer = []; + } + + void arrayElement() { + List list = currentContainer; + currentContainer.add(value); + value = null; + } + + void endArray() { + popContainer(); + } + + /** Read out the final result of parsing a JSON string. */ + get result { + assert(currentContainer == null); return value; } +} - parseObject() { - final object = {}; +typedef _Reviver(var key, var value); - position++; // Eat '{'. +class ReviverJsonListener extends BuildJsonListener { + final _Reviver reviver; + ReviverJsonListener(reviver(key, value)) : this.reviver = reviver; - if (!isToken(RBRACE)) { - while (true) { - final String key = parseString(); - if (!isToken(COLON)) error("Expected ':' when parsing object"); - position++; - object[key] = parseValue(); - - if (!isToken(COMMA)) break; - position++; // Skip ','. - }; - - if (!isToken(RBRACE)) error("Expected '}' at end of object"); - } - position++; - - return object; + void arrayElement() { + List list = currentContainer; + value = reviver(list.length, value); + super.arrayElement(); } - parseList() { - final list = []; - - position++; // Eat '['. - - if (!isToken(RBRACKET)) { - while (true) { - list.add(parseValue()); - - if (!isToken(COMMA)) break; - position++; - }; - - if (!isToken(RBRACKET)) error("Expected ']' at end of list"); - } - position++; - - return list; + void propertyValue() { + value = reviver(key, value); + super.propertyValue(); } - String parseString() { - if (!isToken(STRING_LITERAL)) error("Expected string literal"); - - position++; // Eat '"'. - - List charCodes = new List(); - while (true) { - int c = char(); - if (c == QUOTE) { - position++; - break; - } - if (c == BACKSLASH) { - position++; - if (position == length) { - error('\\ at the end of input'); - } - - switch (char()) { - case QUOTE: - c = QUOTE; - break; - case BACKSLASH: - c = BACKSLASH; - break; - case SLASH: - c = SLASH; - break; - case CHAR_B: - c = BACKSPACE; - break; - case CHAR_N: - c = NEW_LINE; - break; - case CHAR_R: - c = CARRIAGE_RETURN; - break; - case CHAR_F: - c = FORM_FEED; - break; - case CHAR_T: - c = TAB; - break; - case CHAR_U: - if (position + 5 > length) { - error('Invalid unicode esacape sequence'); - } - final codeString = json.substring(position + 1, position + 5); - try { - c = int.parse('0x${codeString}'); - } catch (e) { - error('Invalid unicode esacape sequence'); - } - position += 4; - break; - default: - error('Invalid esacape sequence in string literal'); - } - } - charCodes.add(c); - position++; - } - - return new String.fromCharCodes(charCodes); - } - - num parseNumber() { - if (!isToken(NUMBER_LITERAL)) error('Expected number literal'); - - final int startPos = position; - int char = char(); - if (identical(char, MINUS)) char = nextChar(); - if (identical(char, CHAR_0)) { - char = nextChar(); - } else if (isDigit(char)) { - char = nextChar(); - while (isDigit(char)) char = nextChar(); - } else { - error('Expected digit when parsing number'); - } - - bool isInt = true; - if (identical(char, DOT)) { - char = nextChar(); - if (isDigit(char)) { - char = nextChar(); - isInt = false; - while (isDigit(char)) char = nextChar(); - } else { - error('Expected digit following comma'); - } - } - - if (identical(char, CHAR_E) || identical(char, CHAR_CAPITAL_E)) { - char = nextChar(); - if (identical(char, MINUS) || identical(char, PLUS)) char = nextChar(); - if (isDigit(char)) { - char = nextChar(); - isInt = false; - while (isDigit(char)) char = nextChar(); - } else { - error('Expected digit following \'e\' or \'E\''); - } - } - - String number = json.substring(startPos, position); - if (isInt) { - return int.parse(number); - } else { - return double.parse(number); - } - } - - bool isChar(int char) { - if (position >= length) return false; - return json.charCodeAt(position) == char; - } - - bool isDigit(int char) { - return char >= CHAR_0 && char <= CHAR_9; - } - - bool isToken(int tokenKind) => token() == tokenKind; - - int char() { - if (position >= length) { - error('Unexpected end of JSON stream'); - } - return json.charCodeAt(position); - } - - int nextChar() { - position++; - if (position >= length) return 0; - return json.charCodeAt(position); - } - - int token() { - while (true) { - if (position >= length) return null; - int char = json.charCodeAt(position); - int token = tokens[char]; - if (identical(token, WHITESPACE)) { - position++; - continue; - } - if (token == null) return 0; - return token; - } - } - - void error(String message) { - throw message; + get result { + return reviver("", value); } } +class JsonParser { + // A simple non-recursive state-based parser for JSON. + // + // Literal values accepted in states ARRAY_EMPTY, ARRAY_COMMA, OBJECT_COLON + // and strings also in OBJECT_EMPTY, OBJECT_COMMA. + // VALUE STRING : , } ] Transitions to + // EMPTY X X -> END + // ARRAY_EMPTY X X @ -> ARRAY_VALUE / pop + // ARRAY_VALUE @ @ -> ARRAY_COMMA / pop + // ARRAY_COMMA X X -> ARRAY_VALUE + // OBJECT_EMPTY X @ -> OBJECT_KEY / pop + // OBJECT_KEY @ -> OBJECT_COLON + // OBJECT_COLON X X -> OBJECT_VALUE + // OBJECT_VALUE @ @ -> OBJECT_COMMA / pop + // OBJECT_COMMA X -> OBJECT_KEY + // END + // Starting a new array or object will push the current state. The "pop" + // above means restoring this state and then marking it as an ended value. + // X means generic handling, @ means special handling for just that + // state - that is, values are handled generically, only punctuation + // cares about the current state. + // Values for states are chosen so bits 0 and 1 tell whether + // a string/value is allowed, and setting bits 0 through 2 after a value + // gets to the next state (not empty, doesn't allow a value). + + // State building-block constants. + static const int INSIDE_ARRAY = 1; + static const int INSIDE_OBJECT = 2; + static const int AFTER_COLON = 3; // Always inside object. + + static const int ALLOW_STRING_MASK = 8; // Allowed if zero. + static const int ALLOW_VALUE_MASK = 4; // Allowed if zero. + static const int ALLOW_VALUE = 0; + static const int STRING_ONLY = 4; + static const int NO_VALUES = 12; + + // Objects and arrays are "empty" until their first property/element. + static const int EMPTY = 0; + static const int NON_EMPTY = 16; + static const int EMPTY_MASK = 16; // Empty if zero. + + + static const int VALUE_READ_BITS = NO_VALUES | NON_EMPTY; + + // Actual states. + static const int STATE_INITIAL = EMPTY | ALLOW_VALUE; + static const int STATE_END = NON_EMPTY | NO_VALUES; + + static const int STATE_ARRAY_EMPTY = INSIDE_ARRAY | EMPTY | ALLOW_VALUE; + static const int STATE_ARRAY_VALUE = INSIDE_ARRAY | NON_EMPTY | NO_VALUES; + static const int STATE_ARRAY_COMMA = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE; + + static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY; + static const int STATE_OBJECT_KEY = INSIDE_OBJECT | NON_EMPTY | NO_VALUES; + static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE; + static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES; + static const int STATE_OBJECT_COMMA = INSIDE_OBJECT | NON_EMPTY | STRING_ONLY; + + // Character code constants. + static const int BACKSPACE = 0x08; + static const int TAB = 0x09; + static const int NEWLINE = 0x0a; + static const int CARRIAGE_RETURN = 0x0d; + static const int FORM_FEED = 0x0c; + static const int SPACE = 0x20; + static const int QUOTE = 0x22; + static const int PLUS = 0x2b; + static const int COMMA = 0x2c; + static const int MINUS = 0x2d; + static const int DECIMALPOINT = 0x2e; + static const int SLASH = 0x2f; + static const int CHAR_0 = 0x30; + static const int CHAR_9 = 0x39; + static const int COLON = 0x3a; + static const int CHAR_E = 0x45; + static const int LBRACKET = 0x5b; + static const int BACKSLASH = 0x5c; + static const int RBRACKET = 0x5d; + static const int CHAR_a = 0x61; + static const int CHAR_b = 0x62; + static const int CHAR_e = 0x65; + static const int CHAR_f = 0x66; + static const int CHAR_l = 0x6c; + static const int CHAR_n = 0x6e; + static const int CHAR_r = 0x72; + static const int CHAR_s = 0x73; + static const int CHAR_t = 0x74; + static const int CHAR_u = 0x75; + static const int LBRACE = 0x7b; + static const int RBRACE = 0x7d; + + final String source; + final JsonListener listener; + JsonParser(this.source, this.listener); + + /** Parses [source], or throws if it fails. */ + void parse() { + final List states = []; + int state = STATE_INITIAL; + int position = 0; + int length = source.length; + while (position < length) { + int char = source.charCodeAt(position); + switch (char) { + case SPACE: + case CARRIAGE_RETURN: + case NEWLINE: + case TAB: + position++; + break; + case QUOTE: + if ((state & ALLOW_STRING_MASK) != 0) fail(position); + position = parseString(position + 1); + state |= VALUE_READ_BITS; + break; + case LBRACKET: + if ((state & ALLOW_VALUE_MASK) != 0) fail(position); + listener.beginArray(); + states.add(state); + state = STATE_ARRAY_EMPTY; + position++; + break; + case LBRACE: + if ((state & ALLOW_VALUE_MASK) != 0) fail(position); + listener.beginObject(); + states.add(state); + state = STATE_OBJECT_EMPTY; + position++; + break; + case CHAR_n: + if ((state & ALLOW_VALUE_MASK) != 0) fail(position); + position = parseNull(position); + state |= VALUE_READ_BITS; + break; + case CHAR_f: + if ((state & ALLOW_VALUE_MASK) != 0) fail(position); + position = parseFalse(position); + state |= VALUE_READ_BITS; + break; + case CHAR_t: + if ((state & ALLOW_VALUE_MASK) != 0) fail(position); + position = parseTrue(position); + state |= VALUE_READ_BITS; + break; + case COLON: + if (state != STATE_OBJECT_KEY) fail(position); + listener.propertyName(); + state = STATE_OBJECT_COLON; + position++; + break; + case COMMA: + if (state == STATE_OBJECT_VALUE) { + listener.propertyValue(); + state = STATE_OBJECT_COMMA; + position++; + } else if (state == STATE_ARRAY_VALUE) { + listener.arrayElement(); + state = STATE_ARRAY_COMMA; + position++; + } else { + fail(position); + } + break; + case RBRACKET: + if (state == STATE_ARRAY_EMPTY) { + listener.endArray(); + } else if (state == STATE_ARRAY_VALUE) { + listener.arrayElement(); + listener.endArray(); + } else { + fail(position); + } + state = states.removeLast() | VALUE_READ_BITS; + position++; + break; + case RBRACE: + if (state == STATE_OBJECT_EMPTY) { + listener.endObject(); + } else if (state == STATE_OBJECT_VALUE) { + listener.propertyValue(); + listener.endObject(); + } else { + fail(position); + } + state = states.removeLast() | VALUE_READ_BITS; + position++; + break; + default: + if ((state & ALLOW_VALUE_MASK) != 0) fail(position); + position = parseNumber(char, position); + state |= VALUE_READ_BITS; + break; + } + } + if (state != STATE_END) fail(position); + } + + /** + * Parses a "true" literal starting at [position]. + * + * [:source[position]:] must be "t". + */ + int parseTrue(int position) { + assert(source.charCodeAt(position) == CHAR_t); + if (source.length < position + 4) fail(position, "Unexpected identifier"); + if (source.charCodeAt(position + 1) != CHAR_r || + source.charCodeAt(position + 2) != CHAR_u || + source.charCodeAt(position + 3) != CHAR_e) { + fail(position); + } + listener.handleBool(true); + return position + 4; + } + + /** + * Parses a "false" literal starting at [position]. + * + * [:source[position]:] must be "f". + */ + int parseFalse(int position) { + assert(source.charCodeAt(position) == CHAR_f); + if (source.length < position + 5) fail(position, "Unexpected identifier"); + if (source.charCodeAt(position + 1) != CHAR_a || + source.charCodeAt(position + 2) != CHAR_l || + source.charCodeAt(position + 3) != CHAR_s || + source.charCodeAt(position + 4) != CHAR_e) { + fail(position); + } + listener.handleBool(false); + return position + 5; + } + + /** Parses a "null" literal starting at [position]. + * + * [:source[position]:] must be "n". + */ + int parseNull(int position) { + assert(source.charCodeAt(position) == CHAR_n); + if (source.length < position + 4) fail(position, "Unexpected identifier"); + if (source.charCodeAt(position + 1) != CHAR_u || + source.charCodeAt(position + 2) != CHAR_l || + source.charCodeAt(position + 3) != CHAR_l) { + fail(position); + } + listener.handleNull(); + return position + 4; + } + + int parseString(int position) { + // Format: '"'([^\x00-\x1f\\\"]|'\\'[bfnrt/\\"])*'"' + // Initial position is right after first '"'. + int start = position; + int char; + do { + if (position == source.length) { + fail(start - 1, "Unterminated string"); + } + char = source.charCodeAt(position); + if (char == QUOTE) { + listener.handleString(source.substring(start, position)); + return position + 1; + } + if (char < SPACE) { + fail(position, "Control character in string"); + } + position++; + } while (char != BACKSLASH); + // Backslash escape detected. Collect character codes for rest of string. + int firstEscape = position - 1; + List chars = []; + while (true) { + if (position == source.length) { + fail(start - 1, "Unterminated string"); + } + char = source.charCodeAt(position); + switch (char) { + case CHAR_b: char = BACKSPACE; break; + case CHAR_f: char = FORM_FEED; break; + case CHAR_n: char = NEWLINE; break; + case CHAR_r: char = CARRIAGE_RETURN; break; + case CHAR_t: char = TAB; break; + case SLASH: + case BACKSLASH: + case QUOTE: + break; + case CHAR_u: { + int hexStart = position - 1; + int value = 0; + for (int i = 0; i < 4; i++) { + position++; + if (position == source.length) { + fail(start - 1, "Unterminated string"); + } + char = source.charCodeAt(position); + char -= 0x30; + if (char < 0) fail(hexStart, "Invalid unicode escape"); + if (char < 10) { + value = value * 16 + char; + } else { + char = (char | 0x20) - 0x31; + if (char < 0 || char > 5) { + fail(hexStart, "Invalid unicode escape"); + } + value = value * 16 + char + 10; + } + } + char = value; + break; + } + default: + if (char < SPACE) fail(position, "Control character in string"); + fail(position, "Unrecognized string escape"); + } + do { + chars.add(char); + position++; + if (position == source.length) fail(start - 1, "Unterminated string"); + char = source.charCodeAt(position); + if (char == QUOTE) { + String result = new String.fromCharCodes(chars); + if (start < firstEscape) { + result = "${source.substring(start, firstEscape)}$result"; + } + listener.handleString(result); + return position + 1; + } + if (char < SPACE) { + fail(position, "Control character in string"); + } + } while (char != BACKSLASH); + position++; + } + } + + int parseNumber(int char, int position) { + // Format: + // '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)? + int start = position; + int length = source.length; + bool isDouble = false; + if (char == MINUS) { + position++; + if (position == length) fail(position, "Missing expected digit"); + char = source.charCodeAt(position); + } + if (char < CHAR_0 || char > CHAR_9) { + fail(position, "Missing expected digit"); + } + int handleLiteral(position) { + String literal = source.substring(start, position); + // This correctly creates -0 for doubles. + num value = (isDouble ? double.parse(literal) : int.parse(literal)); + listener.handleNumber(value); + return position; + } + if (char == CHAR_0) { + position++; + if (position == length) return handleLiteral(position); + char = source.charCodeAt(position); + if (CHAR_0 <= char && char <= CHAR_9) { + fail(position); + } + } else { + do { + position++; + if (position == length) return handleLiteral(position); + char = source.charCodeAt(position); + } while (CHAR_0 <= char && char <= CHAR_9); + } + if (char == DECIMALPOINT) { + isDouble = true; + position++; + if (position == length) fail(position, "Missing expected digit"); + char = source.charCodeAt(position); + if (char < CHAR_0 || char > CHAR_9) fail(position); + do { + position++; + if (position == length) return handleLiteral(position); + char = source.charCodeAt(position); + } while (CHAR_0 <= char && char <= CHAR_9); + } + if (char == CHAR_e || char == CHAR_E) { + isDouble = true; + position++; + if (position == length) fail(position, "Missing expected digit"); + char = source.charCodeAt(position); + if (char == PLUS || char == MINUS) { + position++; + if (position == length) fail(position, "Missing expected digit"); + char = source.charCodeAt(position); + } + if (char < CHAR_0 || char > CHAR_9) { + fail(position, "Missing expected digit"); + } + do { + position++; + if (position == length) return handleLiteral(position); + char = source.charCodeAt(position); + } while (CHAR_0 <= char && char <= CHAR_9); + } + return handleLiteral(position); + } + + void fail(int position, [String message]) { + if (message == null) message = "Unexpected character"; + listener.fail(source, position, message); + // If the listener didn't throw, do it here. + String slice; + int sliceEnd = position + 20; + if (sliceEnd > source.length) { + slice = "'${source.substring(position)}'"; + } else { + slice = "'${source.substring(position, sliceEnd)}...'"; + } + throw new FormatException("Unexpected character at $position: $slice"); + } +} + + class _JsonStringifier { StringBuffer sb; List seen; // TODO: that should be identity set. @@ -471,35 +668,35 @@ class _JsonStringifier { int charCode = s.charCodeAt(i); if (charCode < 32) { needsEscape = true; - charCodes.add(_JsonParser.BACKSLASH); + charCodes.add(JsonParser.BACKSLASH); switch (charCode) { - case _JsonParser.BACKSPACE: - charCodes.add(_JsonParser.CHAR_B); + case JsonParser.BACKSPACE: + charCodes.add(JsonParser.CHAR_b); break; - case _JsonParser.TAB: - charCodes.add(_JsonParser.CHAR_T); + case JsonParser.TAB: + charCodes.add(JsonParser.CHAR_t); break; - case _JsonParser.NEW_LINE: - charCodes.add(_JsonParser.CHAR_N); + case JsonParser.NEWLINE: + charCodes.add(JsonParser.CHAR_n); break; - case _JsonParser.FORM_FEED: - charCodes.add(_JsonParser.CHAR_F); + case JsonParser.FORM_FEED: + charCodes.add(JsonParser.CHAR_f); break; - case _JsonParser.CARRIAGE_RETURN: - charCodes.add(_JsonParser.CHAR_R); + case JsonParser.CARRIAGE_RETURN: + charCodes.add(JsonParser.CHAR_r); break; default: - charCodes.add(_JsonParser.CHAR_U); + charCodes.add(JsonParser.CHAR_u); charCodes.add(hexDigit((charCode >> 12) & 0xf)); charCodes.add(hexDigit((charCode >> 8) & 0xf)); charCodes.add(hexDigit((charCode >> 4) & 0xf)); charCodes.add(hexDigit(charCode & 0xf)); break; } - } else if (charCode == _JsonParser.QUOTE || - charCode == _JsonParser.BACKSLASH) { + } else if (charCode == JsonParser.QUOTE || + charCode == JsonParser.BACKSLASH) { needsEscape = true; - charCodes.add(_JsonParser.BACKSLASH); + charCodes.add(JsonParser.BACKSLASH); charCodes.add(charCode); } else { charCodes.add(charCode); diff --git a/sdk/lib/math/base.dart b/sdk/lib/math/base.dart index 4aab467a288..e75286d4d44 100644 --- a/sdk/lib/math/base.dart +++ b/sdk/lib/math/base.dart @@ -46,12 +46,6 @@ const double SQRT1_2 = 0.7071067811865476; */ const double SQRT2 = 1.4142135623730951; -/** Temporary redirect to [int.parse]. */ -int parseInt(String string) => int.parse(string); - -/** Temporary redirect to [double.parse]. */ -double parseDouble(String string) => double.parse(string); - /** * Returns the lesser of two numbers. * diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart index 1b3ad7b7335..2a2eceab450 100644 --- a/sdk/lib/mirrors/mirrors.dart +++ b/sdk/lib/mirrors/mirrors.dart @@ -14,6 +14,7 @@ library dart.mirrors; +import 'dart:async'; import 'dart:isolate'; part 'mirrors_impl.dart'; diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart index 5ec3b6eda27..c05cd565b0b 100644 --- a/sdk/lib/svg/dart2js/svg_dart2js.dart +++ b/sdk/lib/svg/dart2js/svg_dart2js.dart @@ -2797,16 +2797,64 @@ class LengthList implements JavaScriptIndexingBehavior, List native "*SV // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Length)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Length element) => Collections.contains(this, element); + + void forEach(void f(Length element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Length element)) => new MappedList(this, f); + + Iterable where(bool f(Length element)) => new WhereIterable(this, f); + + bool every(bool f(Length element)) => Collections.every(this, f); + + bool any(bool f(Length element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Length value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Length value)) { + return new SkipWhileIterable(this, test); + } + + Length firstMatching(bool test(Length value), { Length orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Length lastMatching(bool test(Length value), {Length orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Length singleMatching(bool test(Length value)) { + return Collections.singleMatching(this, test); + } + + Length elementAt(int index) { + return this[index]; + } + + // From Collection: void add(Length value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -2816,29 +2864,10 @@ class LengthList implements JavaScriptIndexingBehavior, List native "*SV throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Length)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Length element) => Collections.contains(this, element); - - void forEach(void f(Length element)) => Collections.forEach(this, f); - - Collection map(f(Length element)) => Collections.map(this, [], f); - - Collection filter(bool f(Length element)) => - Collections.filter(this, [], f); - - bool every(bool f(Length element)) => Collections.every(this, f); - - bool some(bool f(Length element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -2858,9 +2887,25 @@ class LengthList implements JavaScriptIndexingBehavior, List native "*SV return Lists.lastIndexOf(this, element, start); } - Length get first => this[0]; + Length get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Length get last => this[length - 1]; + Length get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Length get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Length min([int compare(Length a, Length b)]) => _Collections.minInList(this, compare); + + Length max([int compare(Length a, Length b)]) => _Collections.maxInList(this, compare); Length removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -3323,16 +3368,64 @@ class NumberList implements JavaScriptIndexingBehavior, List native "*SV // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Number)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Number element) => Collections.contains(this, element); + + void forEach(void f(Number element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Number element)) => new MappedList(this, f); + + Iterable where(bool f(Number element)) => new WhereIterable(this, f); + + bool every(bool f(Number element)) => Collections.every(this, f); + + bool any(bool f(Number element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Number value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Number value)) { + return new SkipWhileIterable(this, test); + } + + Number firstMatching(bool test(Number value), { Number orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Number lastMatching(bool test(Number value), {Number orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Number singleMatching(bool test(Number value)) { + return Collections.singleMatching(this, test); + } + + Number elementAt(int index) { + return this[index]; + } + + // From Collection: void add(Number value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -3342,29 +3435,10 @@ class NumberList implements JavaScriptIndexingBehavior, List native "*SV throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Number)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Number element) => Collections.contains(this, element); - - void forEach(void f(Number element)) => Collections.forEach(this, f); - - Collection map(f(Number element)) => Collections.map(this, [], f); - - Collection filter(bool f(Number element)) => - Collections.filter(this, [], f); - - bool every(bool f(Number element)) => Collections.every(this, f); - - bool some(bool f(Number element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -3384,9 +3458,25 @@ class NumberList implements JavaScriptIndexingBehavior, List native "*SV return Lists.lastIndexOf(this, element, start); } - Number get first => this[0]; + Number get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Number get last => this[length - 1]; + Number get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Number get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Number min([int compare(Number a, Number b)]) => _Collections.minInList(this, compare); + + Number max([int compare(Number a, Number b)]) => _Collections.maxInList(this, compare); Number removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -4024,16 +4114,64 @@ class PathSegList implements JavaScriptIndexingBehavior, List native "* // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, PathSeg)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(PathSeg element) => Collections.contains(this, element); + + void forEach(void f(PathSeg element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(PathSeg element)) => new MappedList(this, f); + + Iterable where(bool f(PathSeg element)) => new WhereIterable(this, f); + + bool every(bool f(PathSeg element)) => Collections.every(this, f); + + bool any(bool f(PathSeg element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(PathSeg value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(PathSeg value)) { + return new SkipWhileIterable(this, test); + } + + PathSeg firstMatching(bool test(PathSeg value), { PathSeg orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + PathSeg lastMatching(bool test(PathSeg value), {PathSeg orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + PathSeg singleMatching(bool test(PathSeg value)) { + return Collections.singleMatching(this, test); + } + + PathSeg elementAt(int index) { + return this[index]; + } + + // From Collection: void add(PathSeg value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -4043,29 +4181,10 @@ class PathSegList implements JavaScriptIndexingBehavior, List native "* throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, PathSeg)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(PathSeg element) => Collections.contains(this, element); - - void forEach(void f(PathSeg element)) => Collections.forEach(this, f); - - Collection map(f(PathSeg element)) => Collections.map(this, [], f); - - Collection filter(bool f(PathSeg element)) => - Collections.filter(this, [], f); - - bool every(bool f(PathSeg element)) => Collections.every(this, f); - - bool some(bool f(PathSeg element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -4085,9 +4204,25 @@ class PathSegList implements JavaScriptIndexingBehavior, List native "* return Lists.lastIndexOf(this, element, start); } - PathSeg get first => this[0]; + PathSeg get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - PathSeg get last => this[length - 1]; + PathSeg get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + PathSeg get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + PathSeg min([int compare(PathSeg a, PathSeg b)]) => _Collections.minInList(this, compare); + + PathSeg max([int compare(PathSeg a, PathSeg b)]) => _Collections.maxInList(this, compare); PathSeg removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -4750,16 +4885,64 @@ class StringList implements JavaScriptIndexingBehavior, List native "*SV // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(String element) => Collections.contains(this, element); + + void forEach(void f(String element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(String element)) => new MappedList(this, f); + + Iterable where(bool f(String element)) => new WhereIterable(this, f); + + bool every(bool f(String element)) => Collections.every(this, f); + + bool any(bool f(String element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(String value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(String value)) { + return new SkipWhileIterable(this, test); + } + + String firstMatching(bool test(String value), { String orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + String lastMatching(bool test(String value), {String orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + String singleMatching(bool test(String value)) { + return Collections.singleMatching(this, test); + } + + String elementAt(int index) { + return this[index]; + } + + // From Collection: void add(String value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -4769,29 +4952,10 @@ class StringList implements JavaScriptIndexingBehavior, List native "*SV throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(String element) => Collections.contains(this, element); - - void forEach(void f(String element)) => Collections.forEach(this, f); - - Collection map(f(String element)) => Collections.map(this, [], f); - - Collection filter(bool f(String element)) => - Collections.filter(this, [], f); - - bool every(bool f(String element)) => Collections.every(this, f); - - bool some(bool f(String element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -4811,9 +4975,25 @@ class StringList implements JavaScriptIndexingBehavior, List native "*SV return Lists.lastIndexOf(this, element, start); } - String get first => this[0]; + String get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - String get last => this[length - 1]; + String get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + String get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + String min([int compare(String a, String b)]) => _Collections.minInList(this, compare); + + String max([int compare(String a, String b)]) => _Collections.maxInList(this, compare); String removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -5744,16 +5924,64 @@ class TransformList implements List, JavaScriptIndexingBehavior nativ // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Transform)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Transform element) => Collections.contains(this, element); + + void forEach(void f(Transform element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Transform element)) => new MappedList(this, f); + + Iterable where(bool f(Transform element)) => new WhereIterable(this, f); + + bool every(bool f(Transform element)) => Collections.every(this, f); + + bool any(bool f(Transform element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Transform value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Transform value)) { + return new SkipWhileIterable(this, test); + } + + Transform firstMatching(bool test(Transform value), { Transform orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Transform lastMatching(bool test(Transform value), {Transform orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Transform singleMatching(bool test(Transform value)) { + return Collections.singleMatching(this, test); + } + + Transform elementAt(int index) { + return this[index]; + } + + // From Collection: void add(Transform value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -5763,29 +5991,10 @@ class TransformList implements List, JavaScriptIndexingBehavior nativ throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Transform)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Transform element) => Collections.contains(this, element); - - void forEach(void f(Transform element)) => Collections.forEach(this, f); - - Collection map(f(Transform element)) => Collections.map(this, [], f); - - Collection filter(bool f(Transform element)) => - Collections.filter(this, [], f); - - bool every(bool f(Transform element)) => Collections.every(this, f); - - bool some(bool f(Transform element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -5805,9 +6014,25 @@ class TransformList implements List, JavaScriptIndexingBehavior nativ return Lists.lastIndexOf(this, element, start); } - Transform get first => this[0]; + Transform get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Transform get last => this[length - 1]; + Transform get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Transform get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Transform min([int compare(Transform a, Transform b)]) => _Collections.minInList(this, compare); + + Transform max([int compare(Transform a, Transform b)]) => _Collections.maxInList(this, compare); Transform removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -6152,13 +6377,61 @@ class _ElementInstanceList implements JavaScriptIndexingBehavior, List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ElementInstance)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(ElementInstance element) => Collections.contains(this, element); + + void forEach(void f(ElementInstance element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(ElementInstance element)) => new MappedList(this, f); + + Iterable where(bool f(ElementInstance element)) => new WhereIterable(this, f); + + bool every(bool f(ElementInstance element)) => Collections.every(this, f); + + bool any(bool f(ElementInstance element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(ElementInstance value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(ElementInstance value)) { + return new SkipWhileIterable(this, test); + } + + ElementInstance firstMatching(bool test(ElementInstance value), { ElementInstance orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + ElementInstance lastMatching(bool test(ElementInstance value), {ElementInstance orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + ElementInstance singleMatching(bool test(ElementInstance value)) { + return Collections.singleMatching(this, test); + } + + ElementInstance elementAt(int index) { + return this[index]; + } + // From Collection: void add(ElementInstance value) { @@ -6169,29 +6442,10 @@ class _ElementInstanceList implements JavaScriptIndexingBehavior, List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ElementInstance)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(ElementInstance element) => Collections.contains(this, element); - - void forEach(void f(ElementInstance element)) => Collections.forEach(this, f); - - Collection map(f(ElementInstance element)) => Collections.map(this, [], f); - - Collection filter(bool f(ElementInstance element)) => - Collections.filter(this, [], f); - - bool every(bool f(ElementInstance element)) => Collections.every(this, f); - - bool some(bool f(ElementInstance element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -6213,9 +6467,25 @@ class _ElementInstanceList implements JavaScriptIndexingBehavior, List this[0]; + ElementInstance get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - ElementInstance get last => this[length - 1]; + ElementInstance get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + ElementInstance get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + ElementInstance min([int compare(ElementInstance a, ElementInstance b)]) => _Collections.minInList(this, compare); + + ElementInstance max([int compare(ElementInstance a, ElementInstance b)]) => _Collections.maxInList(this, compare); ElementInstance removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart index 77648fa3835..87124708201 100644 --- a/sdk/lib/svg/dartium/svg_dartium.dart +++ b/sdk/lib/svg/dartium/svg_dartium.dart @@ -3542,16 +3542,64 @@ class LengthList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Length)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Length element) => Collections.contains(this, element); + + void forEach(void f(Length element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Length element)) => new MappedList(this, f); + + Iterable where(bool f(Length element)) => new WhereIterable(this, f); + + bool every(bool f(Length element)) => Collections.every(this, f); + + bool any(bool f(Length element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Length value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Length value)) { + return new SkipWhileIterable(this, test); + } + + Length firstMatching(bool test(Length value), { Length orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Length lastMatching(bool test(Length value), {Length orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Length singleMatching(bool test(Length value)) { + return Collections.singleMatching(this, test); + } + + Length elementAt(int index) { + return this[index]; + } + + // From Collection: void add(Length value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -3561,29 +3609,10 @@ class LengthList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Length)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Length element) => Collections.contains(this, element); - - void forEach(void f(Length element)) => Collections.forEach(this, f); - - Collection map(f(Length element)) => Collections.map(this, [], f); - - Collection filter(bool f(Length element)) => - Collections.filter(this, [], f); - - bool every(bool f(Length element)) => Collections.every(this, f); - - bool some(bool f(Length element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -3603,9 +3632,25 @@ class LengthList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Length get first => this[0]; + Length get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Length get last => this[length - 1]; + Length get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Length get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Length min([int compare(Length a, Length b)]) => _Collections.minInList(this, compare); + + Length max([int compare(Length a, Length b)]) => _Collections.maxInList(this, compare); Length removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -4221,16 +4266,64 @@ class NumberList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Number)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Number element) => Collections.contains(this, element); + + void forEach(void f(Number element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Number element)) => new MappedList(this, f); + + Iterable where(bool f(Number element)) => new WhereIterable(this, f); + + bool every(bool f(Number element)) => Collections.every(this, f); + + bool any(bool f(Number element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Number value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Number value)) { + return new SkipWhileIterable(this, test); + } + + Number firstMatching(bool test(Number value), { Number orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Number lastMatching(bool test(Number value), {Number orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Number singleMatching(bool test(Number value)) { + return Collections.singleMatching(this, test); + } + + Number elementAt(int index) { + return this[index]; + } + + // From Collection: void add(Number value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -4240,29 +4333,10 @@ class NumberList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Number)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Number element) => Collections.contains(this, element); - - void forEach(void f(Number element)) => Collections.forEach(this, f); - - Collection map(f(Number element)) => Collections.map(this, [], f); - - Collection filter(bool f(Number element)) => - Collections.filter(this, [], f); - - bool every(bool f(Number element)) => Collections.every(this, f); - - bool some(bool f(Number element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -4282,9 +4356,25 @@ class NumberList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - Number get first => this[0]; + Number get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Number get last => this[length - 1]; + Number get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Number get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Number min([int compare(Number a, Number b)]) => _Collections.minInList(this, compare); + + Number max([int compare(Number a, Number b)]) => _Collections.maxInList(this, compare); Number removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -5308,16 +5398,64 @@ class PathSegList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, PathSeg)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(PathSeg element) => Collections.contains(this, element); + + void forEach(void f(PathSeg element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(PathSeg element)) => new MappedList(this, f); + + Iterable where(bool f(PathSeg element)) => new WhereIterable(this, f); + + bool every(bool f(PathSeg element)) => Collections.every(this, f); + + bool any(bool f(PathSeg element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(PathSeg value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(PathSeg value)) { + return new SkipWhileIterable(this, test); + } + + PathSeg firstMatching(bool test(PathSeg value), { PathSeg orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + PathSeg lastMatching(bool test(PathSeg value), {PathSeg orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + PathSeg singleMatching(bool test(PathSeg value)) { + return Collections.singleMatching(this, test); + } + + PathSeg elementAt(int index) { + return this[index]; + } + + // From Collection: void add(PathSeg value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -5327,29 +5465,10 @@ class PathSegList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, PathSeg)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(PathSeg element) => Collections.contains(this, element); - - void forEach(void f(PathSeg element)) => Collections.forEach(this, f); - - Collection map(f(PathSeg element)) => Collections.map(this, [], f); - - Collection filter(bool f(PathSeg element)) => - Collections.filter(this, [], f); - - bool every(bool f(PathSeg element)) => Collections.every(this, f); - - bool some(bool f(PathSeg element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -5369,9 +5488,25 @@ class PathSegList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - PathSeg get first => this[0]; + PathSeg get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - PathSeg get last => this[length - 1]; + PathSeg get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + PathSeg get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + PathSeg min([int compare(PathSeg a, PathSeg b)]) => _Collections.minInList(this, compare); + + PathSeg max([int compare(PathSeg a, PathSeg b)]) => _Collections.maxInList(this, compare); PathSeg removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -6240,16 +6375,64 @@ class StringList extends NativeFieldWrapperClass1 implements List { // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(String element) => Collections.contains(this, element); + + void forEach(void f(String element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(String element)) => new MappedList(this, f); + + Iterable where(bool f(String element)) => new WhereIterable(this, f); + + bool every(bool f(String element)) => Collections.every(this, f); + + bool any(bool f(String element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(String value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(String value)) { + return new SkipWhileIterable(this, test); + } + + String firstMatching(bool test(String value), { String orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + String lastMatching(bool test(String value), {String orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + String singleMatching(bool test(String value)) { + return Collections.singleMatching(this, test); + } + + String elementAt(int index) { + return this[index]; + } + + // From Collection: void add(String value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -6259,29 +6442,10 @@ class StringList extends NativeFieldWrapperClass1 implements List { throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, String)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(String element) => Collections.contains(this, element); - - void forEach(void f(String element)) => Collections.forEach(this, f); - - Collection map(f(String element)) => Collections.map(this, [], f); - - Collection filter(bool f(String element)) => - Collections.filter(this, [], f); - - bool every(bool f(String element)) => Collections.every(this, f); - - bool some(bool f(String element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -6301,9 +6465,25 @@ class StringList extends NativeFieldWrapperClass1 implements List { return Lists.lastIndexOf(this, element, start); } - String get first => this[0]; + String get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - String get last => this[length - 1]; + String get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + String get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + String min([int compare(String a, String b)]) => _Collections.minInList(this, compare); + + String max([int compare(String a, String b)]) => _Collections.maxInList(this, compare); String removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -7467,16 +7647,64 @@ class TransformList extends NativeFieldWrapperClass1 implements List // From Iterable: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } - // From Collection: // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Transform)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(Transform element) => Collections.contains(this, element); + + void forEach(void f(Transform element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(Transform element)) => new MappedList(this, f); + + Iterable where(bool f(Transform element)) => new WhereIterable(this, f); + + bool every(bool f(Transform element)) => Collections.every(this, f); + + bool any(bool f(Transform element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(Transform value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(Transform value)) { + return new SkipWhileIterable(this, test); + } + + Transform firstMatching(bool test(Transform value), { Transform orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + Transform lastMatching(bool test(Transform value), {Transform orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Transform singleMatching(bool test(Transform value)) { + return Collections.singleMatching(this, test); + } + + Transform elementAt(int index) { + return this[index]; + } + + // From Collection: void add(Transform value) { throw new UnsupportedError("Cannot add to immutable List."); @@ -7486,29 +7714,10 @@ class TransformList extends NativeFieldWrapperClass1 implements List throw new UnsupportedError("Cannot add to immutable List."); } - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Transform)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(Transform element) => Collections.contains(this, element); - - void forEach(void f(Transform element)) => Collections.forEach(this, f); - - Collection map(f(Transform element)) => Collections.map(this, [], f); - - Collection filter(bool f(Transform element)) => - Collections.filter(this, [], f); - - bool every(bool f(Transform element)) => Collections.every(this, f); - - bool some(bool f(Transform element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -7528,9 +7737,25 @@ class TransformList extends NativeFieldWrapperClass1 implements List return Lists.lastIndexOf(this, element, start); } - Transform get first => this[0]; + Transform get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - Transform get last => this[length - 1]; + Transform get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + Transform get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + Transform min([int compare(Transform a, Transform b)]) => _Collections.minInList(this, compare); + + Transform max([int compare(Transform a, Transform b)]) => _Collections.maxInList(this, compare); Transform removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); @@ -7976,13 +8201,61 @@ class _ElementInstanceList extends NativeFieldWrapperClass1 implements List: - Iterator iterator() { + Iterator get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator(this); } + dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ElementInstance)) { + return Collections.reduce(this, initialValue, combine); + } + + bool contains(ElementInstance element) => Collections.contains(this, element); + + void forEach(void f(ElementInstance element)) => Collections.forEach(this, f); + + String join([String separator]) => Collections.joinList(this, separator); + + List mappedBy(f(ElementInstance element)) => new MappedList(this, f); + + Iterable where(bool f(ElementInstance element)) => new WhereIterable(this, f); + + bool every(bool f(ElementInstance element)) => Collections.every(this, f); + + bool any(bool f(ElementInstance element)) => Collections.any(this, f); + + bool get isEmpty => this.length == 0; + + List take(int n) => new ListView(this, 0, n); + + Iterable takeWhile(bool test(ElementInstance value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) => new ListView(this, n, null); + + Iterable skipWhile(bool test(ElementInstance value)) { + return new SkipWhileIterable(this, test); + } + + ElementInstance firstMatching(bool test(ElementInstance value), { ElementInstance orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + ElementInstance lastMatching(bool test(ElementInstance value), {ElementInstance orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + ElementInstance singleMatching(bool test(ElementInstance value)) { + return Collections.singleMatching(this, test); + } + + ElementInstance elementAt(int index) { + return this[index]; + } + // From Collection: void add(ElementInstance value) { @@ -7993,29 +8266,10 @@ class _ElementInstanceList extends NativeFieldWrapperClass1 implements List collection) { + void addAll(Iterable iterable) { throw new UnsupportedError("Cannot add to immutable List."); } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, ElementInstance)) { - return Collections.reduce(this, initialValue, combine); - } - - bool contains(ElementInstance element) => Collections.contains(this, element); - - void forEach(void f(ElementInstance element)) => Collections.forEach(this, f); - - Collection map(f(ElementInstance element)) => Collections.map(this, [], f); - - Collection filter(bool f(ElementInstance element)) => - Collections.filter(this, [], f); - - bool every(bool f(ElementInstance element)) => Collections.every(this, f); - - bool some(bool f(ElementInstance element)) => Collections.some(this, f); - - bool get isEmpty => this.length == 0; - // From List: void set length(int value) { throw new UnsupportedError("Cannot resize immutable List."); @@ -8037,9 +8291,25 @@ class _ElementInstanceList extends NativeFieldWrapperClass1 implements List this[0]; + ElementInstance get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - ElementInstance get last => this[length - 1]; + ElementInstance get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + ElementInstance get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + ElementInstance min([int compare(ElementInstance a, ElementInstance b)]) => _Collections.minInList(this, compare); + + ElementInstance max([int compare(ElementInstance a, ElementInstance b)]) => _Collections.maxInList(this, compare); ElementInstance removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); diff --git a/sdk/lib/uri/uri.dart b/sdk/lib/uri/uri.dart index 4933d9d625b..6b01a0638c5 100644 --- a/sdk/lib/uri/uri.dart +++ b/sdk/lib/uri/uri.dart @@ -229,6 +229,27 @@ class Uri { return sb.toString(); } + bool operator==(other) { + if (other is! Uri) return false; + Uri uri = other; + return scheme == uri.scheme && + userInfo == uri.userInfo && + domain == uri.domain && + port == uri.port && + path == uri.path && + query == uri.query && + fragment == uri.fragment; + } + + int get hashCode { + int combine(part, current) { + // The sum is truncated to 30 bits to make sure it fits into a Smi. + return (current * 31 + part.hashCode) & 0x3FFFFFFF; + } + return combine(scheme, combine(userInfo, combine(domain, combine(port, + combine(path, combine(query, combine(fragment, 1))))))); + } + static void _addIfNonEmpty(StringBuffer sb, String test, String first, String second) { if ("" != test) { diff --git a/sdk/lib/utf/utf16.dart b/sdk/lib/utf/utf16.dart index 7c67a301f24..4fbb80ff961 100644 --- a/sdk/lib/utf/utf16.dart +++ b/sdk/lib/utf/utf16.dart @@ -113,7 +113,7 @@ List encodeUtf16(String str) => List encodeUtf16be(String str, [bool writeBOM = false]) { List utf16CodeUnits = _stringToUtf16CodeUnits(str); List encoding = - new List(2 * utf16CodeUnits.length + (writeBOM ? 2 : 0)); + new List.fixedLength(2 * utf16CodeUnits.length + (writeBOM ? 2 : 0)); int i = 0; if (writeBOM) { encoding[i++] = UNICODE_UTF_BOM_HI; @@ -133,7 +133,7 @@ List encodeUtf16be(String str, [bool writeBOM = false]) { List encodeUtf16le(String str, [bool writeBOM = false]) { List utf16CodeUnits = _stringToUtf16CodeUnits(str); List encoding = - new List(2 * utf16CodeUnits.length + (writeBOM ? 2 : 0)); + new List.fixedLength(2 * utf16CodeUnits.length + (writeBOM ? 2 : 0)); int i = 0; if (writeBOM) { encoding[i++] = UNICODE_UTF_BOM_LO; @@ -188,13 +188,15 @@ typedef _ListRangeIterator _CodeUnitsProvider(); * provides an iterator on demand and the iterator will only translate bytes * as requested by the user of the iterator. (Note: results are not cached.) */ -class IterableUtf16Decoder implements Iterable { +// TODO(floitsch): Consider removing the extend and switch to implements since +// that's cheaper to allocate. +class IterableUtf16Decoder extends Iterable { final _CodeUnitsProvider codeunitsProvider; final int replacementCodepoint; IterableUtf16Decoder._(this.codeunitsProvider, this.replacementCodepoint); - Utf16CodeUnitDecoder iterator() => + Utf16CodeUnitDecoder get iterator => new Utf16CodeUnitDecoder.fromListRangeIterator(codeunitsProvider(), replacementCodepoint); } @@ -207,6 +209,7 @@ class IterableUtf16Decoder implements Iterable { class Utf16BytesToCodeUnitsDecoder implements _ListRangeIterator { final _ListRangeIterator utf16EncodedBytesIterator; final int replacementCodepoint; + int _current = null; Utf16BytesToCodeUnitsDecoder._fromListRangeIterator( this.utf16EncodedBytesIterator, this.replacementCodepoint); @@ -235,33 +238,36 @@ class Utf16BytesToCodeUnitsDecoder implements _ListRangeIterator { * over-allocates the List containing results. */ List decodeRest() { - List codeunits = new List(remaining); + List codeunits = new List.fixedLength(remaining); int i = 0; - while (hasNext) { - codeunits[i++] = next(); + while (moveNext()) { + codeunits[i++] = current; } if (i == codeunits.length) { return codeunits; } else { - List truncCodeunits = new List(i); + List truncCodeunits = new List.fixedLength(i); truncCodeunits.setRange(0, i, codeunits); return truncCodeunits; } } - bool get hasNext => utf16EncodedBytesIterator.hasNext; + int get current => _current; - int next() { + bool moveNext() { + _current = null; if (utf16EncodedBytesIterator.remaining < 2) { - utf16EncodedBytesIterator.next(); + utf16EncodedBytesIterator.moveNext(); if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF16 at ${utf16EncodedBytesIterator.position}"); } } else { - return decode(); + _current = decode(); + return true; } } @@ -288,16 +294,19 @@ class Utf16beBytesToCodeUnitsDecoder extends Utf16BytesToCodeUnitsDecoder { Utf16beBytesToCodeUnitsDecoder(List utf16EncodedBytes, [ int offset = 0, int length, bool stripBom = true, int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - super._fromListRangeIterator((new _ListRange(utf16EncodedBytes, offset, - length)).iterator(), replacementCodepoint) { + super._fromListRangeIterator( + (new _ListRange(utf16EncodedBytes, offset, length)).iterator, + replacementCodepoint) { if (stripBom && hasUtf16beBom(utf16EncodedBytes, offset, length)) { skip(); } } int decode() { - int hi = utf16EncodedBytesIterator.next(); - int lo = utf16EncodedBytesIterator.next(); + utf16EncodedBytesIterator.moveNext(); + int hi = utf16EncodedBytesIterator.current; + utf16EncodedBytesIterator.moveNext(); + int lo = utf16EncodedBytesIterator.current; return (hi << 8) + lo; } } @@ -310,16 +319,19 @@ class Utf16leBytesToCodeUnitsDecoder extends Utf16BytesToCodeUnitsDecoder { Utf16leBytesToCodeUnitsDecoder(List utf16EncodedBytes, [ int offset = 0, int length, bool stripBom = true, int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - super._fromListRangeIterator((new _ListRange(utf16EncodedBytes, offset, - length)).iterator(), replacementCodepoint) { + super._fromListRangeIterator( + (new _ListRange(utf16EncodedBytes, offset, length)).iterator, + replacementCodepoint) { if (stripBom && hasUtf16leBom(utf16EncodedBytes, offset, length)) { skip(); } } int decode() { - int lo = utf16EncodedBytesIterator.next(); - int hi = utf16EncodedBytesIterator.next(); + utf16EncodedBytesIterator.moveNext(); + int lo = utf16EncodedBytesIterator.current; + utf16EncodedBytesIterator.moveNext(); + int hi = utf16EncodedBytesIterator.current; return (hi << 8) + lo; } } diff --git a/sdk/lib/utf/utf32.dart b/sdk/lib/utf/utf32.dart index e4a13fe617e..b9d9e98b48f 100644 --- a/sdk/lib/utf/utf32.dart +++ b/sdk/lib/utf/utf32.dart @@ -182,12 +182,14 @@ typedef Utf32BytesDecoder Utf32BytesDecoderProvider(); * provides an iterator on demand and the iterator will only translate bytes * as requested by the user of the iterator. (Note: results are not cached.) */ -class IterableUtf32Decoder implements Iterable { +// TODO(floitsch): Consider removing the extend and switch to implements since +// that's cheaper to allocate. +class IterableUtf32Decoder extends Iterable { final Utf32BytesDecoderProvider codeunitsProvider; IterableUtf32Decoder._(this.codeunitsProvider); - Utf32BytesDecoder iterator() => codeunitsProvider(); + Utf32BytesDecoder get iterator => codeunitsProvider(); } /** @@ -196,6 +198,7 @@ class IterableUtf32Decoder implements Iterable { class Utf32BytesDecoder implements _ListRangeIterator { final _ListRangeIterator utf32EncodedBytesIterator; final int replacementCodepoint; + int _current = null; Utf32BytesDecoder._fromListRangeIterator( this.utf32EncodedBytesIterator, this.replacementCodepoint); @@ -219,21 +222,23 @@ class Utf32BytesDecoder implements _ListRangeIterator { } List decodeRest() { - List codeunits = new List(remaining); + List codeunits = new List.fixedLength(remaining); int i = 0; - while (hasNext) { - codeunits[i++] = next(); + while (moveNext()) { + codeunits[i++] = current; } return codeunits; } - bool get hasNext => utf32EncodedBytesIterator.hasNext; + int get current => _current; - int next() { + bool moveNext() { + _current = null; if (utf32EncodedBytesIterator.remaining < 4) { utf32EncodedBytesIterator.skip(utf32EncodedBytesIterator.remaining); if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF32 at ${utf32EncodedBytesIterator.position}"); @@ -241,9 +246,11 @@ class Utf32BytesDecoder implements _ListRangeIterator { } else { int codepoint = decode(); if (_validCodepoint(codepoint)) { - return codepoint; + _current = codepoint; + return true; } else if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF32 at ${utf32EncodedBytesIterator.position}"); @@ -274,18 +281,23 @@ class Utf32beBytesDecoder extends Utf32BytesDecoder { Utf32beBytesDecoder(List utf32EncodedBytes, [int offset = 0, int length, bool stripBom = true, int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - super._fromListRangeIterator((new _ListRange(utf32EncodedBytes, offset, - length)).iterator(), replacementCodepoint) { + super._fromListRangeIterator( + (new _ListRange(utf32EncodedBytes, offset, length)).iterator, + replacementCodepoint) { if (stripBom && hasUtf32beBom(utf32EncodedBytes, offset, length)) { skip(); } } int decode() { - int value = utf32EncodedBytesIterator.next(); - value = (value << 8) + utf32EncodedBytesIterator.next(); - value = (value << 8) + utf32EncodedBytesIterator.next(); - value = (value << 8) + utf32EncodedBytesIterator.next(); + utf32EncodedBytesIterator.moveNext(); + int value = utf32EncodedBytesIterator.current; + utf32EncodedBytesIterator.moveNext(); + value = (value << 8) + utf32EncodedBytesIterator.current; + utf32EncodedBytesIterator.moveNext(); + value = (value << 8) + utf32EncodedBytesIterator.current; + utf32EncodedBytesIterator.moveNext(); + value = (value << 8) + utf32EncodedBytesIterator.current; return value; } } @@ -298,18 +310,23 @@ class Utf32leBytesDecoder extends Utf32BytesDecoder { Utf32leBytesDecoder(List utf32EncodedBytes, [int offset = 0, int length, bool stripBom = true, int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - super._fromListRangeIterator((new _ListRange(utf32EncodedBytes, offset, - length)).iterator(), replacementCodepoint) { + super._fromListRangeIterator( + (new _ListRange(utf32EncodedBytes, offset, length)).iterator, + replacementCodepoint) { if (stripBom && hasUtf32leBom(utf32EncodedBytes, offset, length)) { skip(); } } int decode() { - int value = (utf32EncodedBytesIterator.next()); - value += (utf32EncodedBytesIterator.next() << 8); - value += (utf32EncodedBytesIterator.next() << 16); - value += (utf32EncodedBytesIterator.next() << 24); + utf32EncodedBytesIterator.moveNext(); + int value = utf32EncodedBytesIterator.current; + utf32EncodedBytesIterator.moveNext(); + value += (utf32EncodedBytesIterator.current << 8); + utf32EncodedBytesIterator.moveNext(); + value += (utf32EncodedBytesIterator.current << 16); + utf32EncodedBytesIterator.moveNext(); + value += (utf32EncodedBytesIterator.current << 24); return value; } } diff --git a/sdk/lib/utf/utf8.dart b/sdk/lib/utf/utf8.dart index fff010bdb5f..4bf216f8095 100644 --- a/sdk/lib/utf/utf8.dart +++ b/sdk/lib/utf/utf8.dart @@ -86,7 +86,7 @@ List codepointsToUtf8( } } - List encoded = new List(encodedLength); + List encoded = new List.fixedLength(encodedLength); int insertAt = 0; for (int value in source) { if (value < 0 || value > UNICODE_VALID_RANGE_MAX) { @@ -129,7 +129,9 @@ List utf8ToCodepoints( * provides an iterator on demand and the iterator will only translate bytes * as requested by the user of the iterator. (Note: results are not cached.) */ -class IterableUtf8Decoder implements Iterable { +// TODO(floitsch): Consider removing the extend and switch to implements since +// that's cheaper to allocate. +class IterableUtf8Decoder extends Iterable { final List bytes; final int offset; final int length; @@ -138,8 +140,8 @@ class IterableUtf8Decoder implements Iterable { IterableUtf8Decoder(this.bytes, [this.offset = 0, this.length = null, this.replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]); - Utf8Decoder iterator() => new Utf8Decoder(bytes, offset, length, - replacementCodepoint); + Utf8Decoder get iterator => + new Utf8Decoder(bytes, offset, length, replacementCodepoint); } /** @@ -153,55 +155,63 @@ class IterableUtf8Decoder implements Iterable { class Utf8Decoder implements Iterator { final _ListRangeIterator utf8EncodedBytesIterator; final int replacementCodepoint; + int _current = null; Utf8Decoder(List utf8EncodedBytes, [int offset = 0, int length, this.replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - utf8EncodedBytesIterator = (new _ListRange(utf8EncodedBytes, offset, - length)).iterator(); + utf8EncodedBytesIterator = + (new _ListRange(utf8EncodedBytes, offset, length)).iterator; Utf8Decoder._fromListRangeIterator(_ListRange source, [ this.replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - utf8EncodedBytesIterator = source.iterator(); + utf8EncodedBytesIterator = source.iterator; /** Decode the remaininder of the characters in this decoder * into a [List]. */ List decodeRest() { - List codepoints = new List(utf8EncodedBytesIterator.remaining); + List codepoints = new List.fixedLength(utf8EncodedBytesIterator.remaining); int i = 0; - while (hasNext) { - codepoints[i++] = next(); + while (moveNext()) { + codepoints[i++] = current; } if (i == codepoints.length) { return codepoints; } else { - List truncCodepoints = new List(i); + List truncCodepoints = new List.fixedLength(i); truncCodepoints.setRange(0, i, codepoints); return truncCodepoints; } } - bool get hasNext => utf8EncodedBytesIterator.hasNext; + int get current => _current; - int next() { - int value = utf8EncodedBytesIterator.next(); + bool moveNext() { + _current = null; + + if (!utf8EncodedBytesIterator.moveNext()) return false; + + int value = utf8EncodedBytesIterator.current; int additionalBytes = 0; if (value < 0) { if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF8 at ${utf8EncodedBytesIterator.position}"); } } else if (value <= _UTF8_ONE_BYTE_MAX) { - return value; + _current = value; + return true; } else if (value < _UTF8_FIRST_BYTE_OF_TWO_BASE) { if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF8 at ${utf8EncodedBytesIterator.position}"); @@ -222,14 +232,15 @@ class Utf8Decoder implements Iterator { value -= _UTF8_FIRST_BYTE_OF_SIX_BASE; additionalBytes = 5; } else if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF8 at ${utf8EncodedBytesIterator.position}"); } int j = 0; - while (j < additionalBytes && utf8EncodedBytesIterator.hasNext) { - int nextValue = utf8EncodedBytesIterator.next(); + while (j < additionalBytes && utf8EncodedBytesIterator.moveNext()) { + int nextValue = utf8EncodedBytesIterator.current; if (nextValue > _UTF8_ONE_BYTE_MAX && nextValue < _UTF8_FIRST_BYTE_OF_TWO_BASE) { value = ((value << 6) | (nextValue & _UTF8_LO_SIX_BIT_MASK)); @@ -251,9 +262,11 @@ class Utf8Decoder implements Iterator { (additionalBytes == 3 && value > _UTF8_THREE_BYTE_MAX); bool inRange = value <= UNICODE_VALID_RANGE_MAX; if (validSequence && nonOverlong && inRange) { - return value; + _current = value; + return true; } else if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; + return true; } else { throw new ArgumentError( "Invalid UTF8 at ${utf8EncodedBytesIterator.position - j}"); diff --git a/sdk/lib/utf/utf_core.dart b/sdk/lib/utf/utf_core.dart index cdc1ddffe8a..15ca45e356e 100644 --- a/sdk/lib/utf/utf_core.dart +++ b/sdk/lib/utf/utf_core.dart @@ -45,8 +45,10 @@ const int UNICODE_UTF16_LO_MASK = 0x3ff; * Encode code points as UTF16 code units. */ List _codepointsToUtf16CodeUnits( - List codepoints, [int offset = 0, int length, - int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) { + List codepoints, + [int offset = 0, + int length, + int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) { _ListRange listRange = new _ListRange(codepoints, offset, length); int encodedLength = 0; @@ -62,7 +64,7 @@ List _codepointsToUtf16CodeUnits( } } - List codeUnitsBuffer = new List(encodedLength); + List codeUnitsBuffer = new List.fixedLength(encodedLength); int j = 0; for (int value in listRange) { if ((value >= 0 && value < UNICODE_UTF16_RESERVED_LO) || @@ -91,18 +93,18 @@ List _utf16CodeUnitsToCodepoints( List utf16CodeUnits, [int offset = 0, int length, int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) { _ListRangeIterator source = - (new _ListRange(utf16CodeUnits, offset, length)).iterator(); + (new _ListRange(utf16CodeUnits, offset, length)).iterator; Utf16CodeUnitDecoder decoder = new Utf16CodeUnitDecoder .fromListRangeIterator(source, replacementCodepoint); - List codepoints = new List(source.remaining); + List codepoints = new List.fixedLength(source.remaining); int i = 0; - while (decoder.hasNext) { - codepoints[i++] = decoder.next(); + while (decoder.moveNext()) { + codepoints[i++] = decoder.current; } if (i == codepoints.length) { return codepoints; } else { - List codepointTrunc = new List(i); + List codepointTrunc = new List.fixedLength(i); codepointTrunc.setRange(0, i, codepoints); return codepointTrunc; } @@ -117,26 +119,30 @@ List _utf16CodeUnitsToCodepoints( class Utf16CodeUnitDecoder implements Iterator { final _ListRangeIterator utf16CodeUnitIterator; final int replacementCodepoint; + int _current = null; Utf16CodeUnitDecoder(List utf16CodeUnits, [int offset = 0, int length, int this.replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) : - utf16CodeUnitIterator = (new _ListRange(utf16CodeUnits, offset, length)) - .iterator(); + utf16CodeUnitIterator = + (new _ListRange(utf16CodeUnits, offset, length)).iterator; Utf16CodeUnitDecoder.fromListRangeIterator( _ListRangeIterator this.utf16CodeUnitIterator, int this.replacementCodepoint); - Iterator iterator() => this; + Iterator get iterator => this; - bool get hasNext => utf16CodeUnitIterator.hasNext; + int get current => _current; - int next() { - int value = utf16CodeUnitIterator.next(); + bool moveNext() { + _current = null; + if (!utf16CodeUnitIterator.moveNext()) return false; + + int value = utf16CodeUnitIterator.current; if (value < 0) { if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; } else { throw new ArgumentError( "Invalid UTF16 at ${utf16CodeUnitIterator.position}"); @@ -144,35 +150,36 @@ class Utf16CodeUnitDecoder implements Iterator { } else if (value < UNICODE_UTF16_RESERVED_LO || (value > UNICODE_UTF16_RESERVED_HI && value <= UNICODE_PLANE_ONE_MAX)) { // transfer directly - return value; + _current = value; } else if (value < UNICODE_UTF16_SURROGATE_UNIT_1_BASE && - utf16CodeUnitIterator.hasNext) { + utf16CodeUnitIterator.moveNext()) { // merge surrogate pair - int nextValue = utf16CodeUnitIterator.next(); + int nextValue = utf16CodeUnitIterator.current; if (nextValue >= UNICODE_UTF16_SURROGATE_UNIT_1_BASE && nextValue <= UNICODE_UTF16_RESERVED_HI) { value = (value - UNICODE_UTF16_SURROGATE_UNIT_0_BASE) << 10; value += UNICODE_UTF16_OFFSET + (nextValue - UNICODE_UTF16_SURROGATE_UNIT_1_BASE); - return value; + _current = value; } else { if (nextValue >= UNICODE_UTF16_SURROGATE_UNIT_0_BASE && nextValue < UNICODE_UTF16_SURROGATE_UNIT_1_BASE) { utf16CodeUnitIterator.backup(); } if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; } else { throw new ArgumentError( "Invalid UTF16 at ${utf16CodeUnitIterator.position}"); } } } else if (replacementCodepoint != null) { - return replacementCodepoint; + _current = replacementCodepoint; } else { throw new ArgumentError( "Invalid UTF16 at ${utf16CodeUnitIterator.position}"); } + return true; } } @@ -181,7 +188,9 @@ class Utf16CodeUnitDecoder implements Iterator { * range within a source list. DO NOT MODIFY the underlying list while * iterating over it. The results of doing so are undefined. */ -class _ListRange implements Iterable { +// TODO(floitsch): Consider removing the extend and switch to implements since +// that's cheaper to allocate. +class _ListRange extends Iterable { final List _source; final int _offset; final int _length; @@ -201,7 +210,7 @@ class _ListRange implements Iterable { } } - _ListRangeIterator iterator() => + _ListRangeIterator get iterator => new _ListRangeIteratorImpl(_source, _offset, _offset + _length); int get length => _length; @@ -213,8 +222,8 @@ class _ListRange implements Iterable { * and move forward/backward within the iterator. */ abstract class _ListRangeIterator implements Iterator { - bool hasNext; - int next(); + bool moveNext(); + int get current; int get position; void backup([by]); int get remaining; @@ -226,11 +235,12 @@ class _ListRangeIteratorImpl implements _ListRangeIterator { int _offset; final int _end; - _ListRangeIteratorImpl(this._source, this._offset, this._end); + _ListRangeIteratorImpl(this._source, int offset, this._end) + : _offset = offset - 1; - bool get hasNext => _offset < _end; + int get current => _source[_offset]; - int next() => _source[_offset++]; + bool moveNext() => ++_offset < _end; int get position => _offset; @@ -238,7 +248,7 @@ class _ListRangeIteratorImpl implements _ListRangeIterator { _offset -= by; } - int get remaining => _end - _offset; + int get remaining => _end - _offset - 1; void skip([int count = 1]) { _offset += count; diff --git a/tests/benchmark_smoke/benchmark_lib.dart b/tests/benchmark_smoke/benchmark_lib.dart index 8fb84cb57ff..33233adc8ad 100644 --- a/tests/benchmark_smoke/benchmark_lib.dart +++ b/tests/benchmark_smoke/benchmark_lib.dart @@ -4,7 +4,6 @@ library benchmark_lib; -import 'dart:json'; import 'dart:html'; import 'dart:math' as Math; diff --git a/tests/co19/co19-compiler.status b/tests/co19/co19-compiler.status index da362cbb3cc..f2af1531940 100644 --- a/tests/co19/co19-compiler.status +++ b/tests/co19/co19-compiler.status @@ -138,6 +138,11 @@ Language/11_Expressions/22_Equality_A02_t03: Fail, OK # co19 issue 169 +LibTest/math/parseDouble_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseDouble_A02_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A02_t01: Fail, OK # co19 issue 317 + [ $runtime == drt && ($compiler == none || $compiler == frog) ] *: Skip diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status index 3d66bc6276f..f31b5ebadd8 100644 --- a/tests/co19/co19-dart2dart.status +++ b/tests/co19/co19-dart2dart.status @@ -443,6 +443,10 @@ LibTest/math/sin_A01_t01: Fail # Inherited from VM. LibTest/math/tan_A01_t01: Fail # Issue co19 - 44 +LibTest/math/parseDouble_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A02_t01: Fail, OK # co19 issue 317 + LibTest/core/StringBuffer/addAll_A02_t01: Fail, OK # co19 issue 355 LibTest/core/StringBuffer/add_A02_t01: Fail, OK # co19 issue 355 LibTest/core/StringBuffer/isEmpty_A01_t01: Fail, OK # co19 issue 355 diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status index 43b3c2f4584..15c71f30132 100644 --- a/tests/co19/co19-dart2js.status +++ b/tests/co19/co19-dart2js.status @@ -171,6 +171,10 @@ Language/07_Classes/6_Constructors/2_Factories_A01_t05: Fail [ $compiler == dart2js && ($system == linux || $system == macos)] LibTest/math/exp_A01_t01: Fail # TODO(ahe): Please triage this failure. +LibTest/math/parseDouble_A02_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A02_t01: Fail, OK # co19 issue 317 + [ $compiler == dart2js && $unchecked ] LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A03_t01: Fail # TODO(ahe): Please triage this failure. diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status index 3a130295203..cbecf23272a 100644 --- a/tests/co19/co19-runtime.status +++ b/tests/co19/co19-runtime.status @@ -2,6 +2,10 @@ # 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. +[ $compiler == none && $runtime == vm && $checked ] +LibTest/core/Strings/concatAll_A04_t01: Fail, OK # checks for ArgumentError. TypeError is ok too. issue 6719 +LibTest/core/Strings/join_A04_t01: Fail, OK # checks for ArgumentError. TypeError is ok too. issue 6719 + [ $compiler == none && $runtime == vm ] Language/13_Libraries_and_Scripts/1_Imports_A02_t21: Crash # Dart issue 6060 Language/13_Libraries_and_Scripts/1_Imports_A02_t22: Crash # Dart issue 6060 @@ -126,13 +130,183 @@ Language/05_Variables/05_Variables_A05_t15: Fail # Dart issue 5885 Language/05_Variables/1_Evaluation_of_Implicit_Variable_Getters_A01_t02: Fail # Dart issue 5802 Language/05_Variables/1_Evaluation_of_Implicit_Variable_Getters_A01_t05: Fail # Dart issue 5894 -LibTest/isolate/isolate_api/port_A01_t01: Skip # Times out. +LibTest/core/Queue/some_A01_t06: Fail, OK # behavior of some is undefined when underlying collection changes, issue 6719 +LibTest/core/Queue/every_A01_t06: Fail, OK # behavior of some is undefined when underlying collection changes, issue 6719 +LibTest/core/Queue/forEach_A01_t04: Fail, OK # behavior of some is undefined when underlying collection changes, issue 6719 + +LibTest/core/List/length_A04_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/removeRange_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/addAll_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/removeLast_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/List_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/insertRange_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/List_A01_t02: Fail, OK # List constructors, issue 6719 +LibTest/core/List/clear_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/addLast_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/add_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/length_A04_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/removeRange_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/addAll_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/removeLast_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/List_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/insertRange_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/List_A01_t02: Fail, OK # List constructors, issue 6719 +LibTest/core/List/clear_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/addLast_A02_t01: Fail, OK # List constructors, issue 6719 +LibTest/core/List/add_A02_t01: Fail, OK # List constructors, issue 6719 + +LibTest/core/List/last_A02_t01: Fail # List.last throws a StateError, issue 6719 + +LibTest/core/double/toInt_A01_t03: Fail # conversion to integer throws UnsupportedError for NaN/Infinity now, issue 6719 +LibTest/core/double/toInt_A01_t04: Fail # conversion to integer throws UnsupportedError for NaN/Infinity now, issue 6719 + +LibTest/core/double/operator_truncating_division_A01_t01: Fail # ~/ returns ints, issue 6719 +LibTest/core/double/operator_truncating_division_A01_t03: Fail # ~/ returns ints, issue 6719 +LibTest/core/double/operator_truncating_division_A01_t04: Fail # ~/ returns ints, issue 6719 +LibTest/core/double/operator_truncating_division_A01_t05: Fail # ~/ returns ints, issue 6719 +LibTest/core/double/operator_truncating_division_A01_t06: Fail # ~/ returns ints, issue 6719 +LibTest/core/double/isNaN_A01_t03: Fail # ~/ returns ints, issue 6719 +LibTest/core/double/double_class_A01_t01: Fail # ~/ returns ints, issue 6719 + +LibTest/core/RegExp/stringMatch_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/pattern_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/RegExp_A01_t02: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A04_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A03_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Disjunction_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A06_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A03_t03: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/hasMatch_A01_t02: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/multiLine_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/RegExp_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/ignoreCase_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/replaceAll_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/split_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/replaceFirst_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/split_A01_t02: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/end_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/groups_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/str_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/pattern_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/groupCount_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/group_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/start_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/stringMatch_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/pattern_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/RegExp_A01_t02: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A04_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A03_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Disjunction_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A06_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A03_t03: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/hasMatch_A01_t02: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/multiLine_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/RegExp_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/ignoreCase_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/replaceAll_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/split_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/replaceFirst_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/split_A01_t02: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/end_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/groups_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/str_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/pattern_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/groupCount_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/group_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/start_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/firstMatch_A03_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/stringMatch_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/hasMatch_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/allMatches_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/contains_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/operator_subscript_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/groups_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/group_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/firstMatch_A03_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/stringMatch_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/hasMatch_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/RegExp/allMatches_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/String/contains_A01_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/operator_subscript_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/groups_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 +LibTest/core/Match/group_A02_t01: Fail # Regexp multiLine, ignoreCase -> isMultiLine, isCaseSensitive, issue 6719 + +LibTest/core/Set/some_A01_t03: Fail, OK # some -> any, issue 6719 +LibTest/core/Set/some_A01_t02: Fail, OK # some -> any, issue 6719 +LibTest/core/Set/some_A01_t01: Fail, OK # some -> any, issue 6719 +LibTest/core/List/some_A02_t01: Fail, OK # some -> any, issue 6719 +LibTest/core/List/some_A01_t02: Fail, OK # some -> any, issue 6719 +LibTest/core/List/some_A01_t01: Fail, OK # some -> any, issue 6719 +LibTest/core/Queue/some_A01_t05: Fail, OK # some -> any, issue 6719 +LibTest/core/Queue/some_A01_t03: Fail, OK # some -> any, issue 6719 +LibTest/core/Queue/some_A01_t02: Fail, OK # some -> any, issue 6719 +LibTest/core/Queue/some_A01_t01: Fail, OK # some -> any, issue 6719 +LibTest/core/Queue/some_A01_t04: Fail, OK # some -> any, issue 6719 + +LibTest/core/Queue/filter_A01_t04: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t06: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t02: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t03: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t05: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A04_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A01_t02: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A02_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A01_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/Set/filter_A01_t02: Fail, OK # filter->where, issue 6719 +LibTest/core/Set/filter_A01_t03: Fail, OK # filter->where, issue 6719 +LibTest/core/Set/filter_A01_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t04: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t06: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t02: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t03: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t05: Fail, OK # filter->where, issue 6719 +LibTest/core/Queue/filter_A01_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A04_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A01_t02: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A02_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/List/filter_A01_t01: Fail, OK # filter->where, issue 6719 +LibTest/core/Set/filter_A01_t02: Fail, OK # filter->where, issue 6719 +LibTest/core/Set/filter_A01_t03: Fail, OK # filter->where, issue 6719 +LibTest/core/Set/filter_A01_t01: Fail, OK # filter->where, issue 6719 + +Language/12_Statements/08_Do_A02_t01: Fail, OK # iterator-change, issue 6719 +Language/12_Statements/06_For/2_For_in_A01_t01: Fail, OK # iterator-change, issue 6719 +Language/12_Statements/06_For/2_For_in_A01_t05: Fail, OK # iterator-change, issue 6719 +Language/12_Statements/07_While_A02_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/iterator_hasNext_A01_t02: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/iterator_hasNext_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/iterator_A01_t02: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/iterator_next_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/iterator_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/iterator_next_A01_t02: Fail, OK # iterator-change, issue 6719 +LibTest/core/List/iterator_hasNext_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/List/iterator_next_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/List/iterator_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/List/List.from_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/RegExp/allMatches_A01_t01: Fail, OK # iterator-change, issue 6719 +LibTest/core/Queue/Queue.from_A01_t02: Fail # iterator-change, issue 6719 +LibTest/core/Set/Set.from_A01_t02: Fail # iterator-change, issue 6719 +LibTest/core/Queue/iterator_next_A02_t01: Fail # iterator-change, issue 6719 +LibTest/core/List/iterator_next_A02_t01: Fail # iterator-change, issue 6719 +LibTest/core/Queue/iterator_next_A02_t01: Fail # iterator-change, issue 6719 +LibTest/core/Queue/Queue.from_A01_t02: Fail # iterator-change, issue 6719 +LibTest/core/List/iterator_next_A02_t01: Fail # iterator-change, issue 6719 +LibTest/core/Set/Set.from_A01_t02: Fail # iterator-change, issue 6719 Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t01: Fail # issue 6085 Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t02: Fail # issue 6085 Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t03: Fail # issue 6085 +LibTest/math/parseDouble_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A01_t01: Fail, OK # co19 issue 317 +LibTest/math/parseInt_A02_t01: Fail, OK # co19 issue 317 + [ $compiler == none && $runtime == vm && $checked ] Language/12_Statements/09_Switch_A05_t01: Fail # TODO(vm-team): Please triage this failure. @@ -286,3 +460,76 @@ LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash [ $compiler == none && $arch == arm ] *: Skip + + +# Dart bug 6719 +# Fail due to Future being in dart:async now +[ $compiler == none && $runtime == vm ] +LibTest/core/Completer/Completer_A01_t01: fail +LibTest/core/Completer/completeException_A01_t01: fail +LibTest/core/Completer/completeException_A02_t01: fail +LibTest/core/Completer/completeException_A03_t01: fail +LibTest/core/Completer/completeException_A03_t02: fail +LibTest/core/Completer/complete_A01_t01: fail +LibTest/core/Completer/complete_A02_t01: fail +LibTest/core/Completer/complete_A02_t02: fail +LibTest/core/Completer/future_A01_t01: fail +LibTest/core/Future/Future.immediate_A01_t01: fail +LibTest/core/Future/chain_A01_t01: fail +LibTest/core/Future/chain_A01_t02: fail +LibTest/core/Future/chain_A01_t03: fail +LibTest/core/Future/chain_A01_t04: fail +LibTest/core/Future/chain_A01_t05: fail +LibTest/core/Future/chain_A01_t06: fail +LibTest/core/Future/chain_A01_t07: fail +LibTest/core/Future/chain_A01_t08: fail +LibTest/core/Future/chain_A01_t09: fail +LibTest/core/Future/chain_A02_t01: fail +LibTest/core/Future/chain_A02_t02: fail +LibTest/core/Future/chain_A02_t03: fail +LibTest/core/Future/chain_A02_t04: fail +LibTest/core/Future/chain_A03_t01: fail +LibTest/core/Future/exception_A01_t01: fail +LibTest/core/Future/exception_A01_t02: fail +LibTest/core/Future/exception_A02_t01: fail +LibTest/core/Future/handleException_A01_t01: fail +LibTest/core/Future/handleException_A01_t02: fail +LibTest/core/Future/handleException_A01_t03: fail +LibTest/core/Future/handleException_A01_t04: fail +LibTest/core/Future/handleException_A01_t05: fail +LibTest/core/Future/handleException_A01_t06: fail +LibTest/core/Future/handleException_A01_t07: fail +LibTest/core/Future/hasValue_A01_t01: fail +LibTest/core/Future/isComplete_A01_t01: fail +LibTest/core/Future/then_A01_t01: fail +LibTest/core/Future/then_A01_t02: fail +LibTest/core/Future/then_A01_t03: fail +LibTest/core/Future/then_A01_t04: fail +LibTest/core/Future/then_A01_t05: fail +LibTest/core/Future/transform_A01_t01: fail +LibTest/core/Future/transform_A01_t02: fail +LibTest/core/Future/transform_A01_t03: fail +LibTest/core/Future/transform_A01_t04: fail +LibTest/core/Future/transform_A01_t05: fail +LibTest/core/Future/transform_A01_t06: fail +LibTest/core/Future/transform_A01_t07: fail +LibTest/core/Future/transform_A02_t01: fail +LibTest/core/Future/transform_A02_t02: fail +LibTest/core/Future/transform_A02_t03: fail +LibTest/core/Future/transform_A03_t01: fail +LibTest/core/Future/value_A01_t01: fail +LibTest/core/Future/value_A01_t02: fail +LibTest/core/Future/value_A01_t03: fail +LibTest/core/Futures/wait_A01_t01: fail +LibTest/core/Futures/wait_A01_t03: fail +LibTest/core/Futures/wait_A01_t04: fail +LibTest/core/Futures/wait_A01_t05: fail +LibTest/core/Futures/wait_A01_t06: fail +LibTest/core/Futures/wait_A02_t01: fail +LibTest/core/Futures/wait_A02_t02: fail + +[ $compiler == none && $runtime == vm && $unchecked ] +LibTest/core/Future/chain_A02_t05: fail +LibTest/core/Future/transform_A02_t04: fail +[ $compiler == none && $runtime == vm && $checked ] +LibTest/isolate/SendPort/call_A01_t01: fail diff --git a/tests/compiler/dart2js/builtin_equals_test.dart b/tests/compiler/dart2js/builtin_equals_test.dart index 39bb56ac769..a2e7cdac840 100644 --- a/tests/compiler/dart2js/builtin_equals_test.dart +++ b/tests/compiler/dart2js/builtin_equals_test.dart @@ -20,6 +20,6 @@ main() { Expect.isTrue(!generated.contains('eqB')); RegExp regexp = new RegExp('=='); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 4); } diff --git a/tests/compiler/dart2js/closure_codegen_test.dart b/tests/compiler/dart2js/closure_codegen_test.dart index 3f6daf3e850..944446b7c18 100644 --- a/tests/compiler/dart2js/closure_codegen_test.dart +++ b/tests/compiler/dart2js/closure_codegen_test.dart @@ -53,7 +53,7 @@ closureInvocation() { closureBailout() { String generated = compileAll(TEST_BAILOUT); RegExp regexp = new RegExp(r'call\$0: function'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); } diff --git a/tests/compiler/dart2js/code_motion_test.dart b/tests/compiler/dart2js/code_motion_test.dart index f06cd056b39..d14cc696974 100644 --- a/tests/compiler/dart2js/code_motion_test.dart +++ b/tests/compiler/dart2js/code_motion_test.dart @@ -20,8 +20,7 @@ foo(int a, int b, bool param2) { main() { String generated = compile(TEST_ONE, entry: 'foo'); RegExp regexp = new RegExp('a \\+ b'); - Iterator matches = regexp.allMatches(generated).iterator(); - Expect.isTrue(matches.hasNext); - matches.next(); - Expect.isFalse(matches.hasNext); + Iterator matches = regexp.allMatches(generated).iterator; + Expect.isTrue(matches.moveNext()); + Expect.isFalse(matches.moveNext()); } diff --git a/tests/compiler/dart2js/dart_backend_test.dart b/tests/compiler/dart2js/dart_backend_test.dart index 9959ec40269..26641b78fd8 100644 --- a/tests/compiler/dart2js/dart_backend_test.dart +++ b/tests/compiler/dart2js/dart_backend_test.dart @@ -459,7 +459,7 @@ main() { FunctionExpression mainNode = mainElement.parseNode(compiler); FunctionExpression fooNode = mainNode.body.statements.nodes.head.function; LocalPlaceholder fooPlaceholder = - collector.functionScopes[mainElement].localPlaceholders.iterator().next(); + collector.functionScopes[mainElement].localPlaceholders.first; Expect.isTrue(fooPlaceholder.nodes.contains(fooNode.name)); } diff --git a/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart b/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart index b2634394dd2..ae8704255e4 100644 --- a/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart +++ b/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart @@ -27,7 +27,7 @@ main() { compiler.runCompiler(uri); String generated = compiler.assembledCode; RegExp regexp = new RegExp(r"get\$foo"); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); var cls = findElement(compiler, 'A'); Expect.isNotNull(cls); diff --git a/tests/compiler/dart2js/gvn_test.dart b/tests/compiler/dart2js/gvn_test.dart index edc6c822f37..34d9d893f80 100644 --- a/tests/compiler/dart2js/gvn_test.dart +++ b/tests/compiler/dart2js/gvn_test.dart @@ -16,8 +16,7 @@ void foo(bar) { main() { String generated = compile(TEST_ONE, entry: 'foo'); RegExp regexp = new RegExp(r"1 \+ [a-z]+"); - Iterator matches = regexp.allMatches(generated).iterator(); - Expect.isTrue(matches.hasNext); - matches.next(); - Expect.isFalse(matches.hasNext); + Iterator matches = regexp.allMatches(generated).iterator; + Expect.isTrue(matches.moveNext()); + Expect.isFalse(matches.moveNext()); } diff --git a/tests/compiler/dart2js/identity_test.dart b/tests/compiler/dart2js/identity_test.dart index 2b72fe5b4de..1e47d5878f0 100644 --- a/tests/compiler/dart2js/identity_test.dart +++ b/tests/compiler/dart2js/identity_test.dart @@ -18,12 +18,11 @@ main() { // Check that no boolify code is generated. RegExp regexp = new RegExp("=== true"); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; Expect.isFalse(matches.hasNext); regexp = new RegExp("==="); - matches = regexp.allMatches(generated).iterator(); - Expect.isTrue(matches.hasNext); - matches.next(); - Expect.isFalse(matches.hasNext); + matches = regexp.allMatches(generated).iterator; + Expect.isTrue(matches.moveNext()); + Expect.isFalse(matches.moveNext()); } diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart index 1bbb6dd1e3b..fa85c99edf2 100644 --- a/tests/compiler/dart2js/mock_compiler.dart +++ b/tests/compiler/dart2js/mock_compiler.dart @@ -143,7 +143,7 @@ class MockCompiler extends Compiler { var script = new Script(uri, new MockFile(source)); var library = new LibraryElement(script); parseScript(source, library); - library.setExports(library.localScope.values); + library.setExports(library.localScope.values.toList()); return library; } @@ -237,8 +237,10 @@ class MockCompiler extends Compiler { void compareWarningKinds(String text, expectedWarnings, foundWarnings) { var fail = (message) => Expect.fail('$text: $message'); - Iterator expected = expectedWarnings.iterator(); - Iterator found = foundWarnings.iterator(); + HasNextIterator expected = + new HasNextIterator(expectedWarnings.iterator); + HasNextIterator found = + new HasNextIterator(foundWarnings.iterator); while (expected.hasNext && found.hasNext) { Expect.equals(expected.next(), found.next().message.kind); } diff --git a/tests/compiler/dart2js/no_duplicate_constructor_body2_test.dart b/tests/compiler/dart2js/no_duplicate_constructor_body2_test.dart index b5e2674562c..f2de6cf4156 100644 --- a/tests/compiler/dart2js/no_duplicate_constructor_body2_test.dart +++ b/tests/compiler/dart2js/no_duplicate_constructor_body2_test.dart @@ -23,6 +23,6 @@ main() { main() { String generated = compileAll(CODE); RegExp regexp = new RegExp(r'A\$0: function'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); } diff --git a/tests/compiler/dart2js/no_duplicate_constructor_body_test.dart b/tests/compiler/dart2js/no_duplicate_constructor_body_test.dart index 7fc4108d0f2..e25231b8132 100644 --- a/tests/compiler/dart2js/no_duplicate_constructor_body_test.dart +++ b/tests/compiler/dart2js/no_duplicate_constructor_body_test.dart @@ -17,6 +17,6 @@ main() { main() { String generated = compileAll(CODE); RegExp regexp = new RegExp(r'\$.A = {"": "[A-za-z]+;"'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); } diff --git a/tests/compiler/dart2js/no_duplicate_stub_test.dart b/tests/compiler/dart2js/no_duplicate_stub_test.dart index fa0fe59fd66..3213529a77f 100644 --- a/tests/compiler/dart2js/no_duplicate_stub_test.dart +++ b/tests/compiler/dart2js/no_duplicate_stub_test.dart @@ -30,6 +30,6 @@ baz(a) { main() { String generated = compileAll(TEST); RegExp regexp = new RegExp('foo\\\$1\\\$a: function'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); } diff --git a/tests/compiler/dart2js/pretty_parameter_test.dart b/tests/compiler/dart2js/pretty_parameter_test.dart index 03f199f57e5..6831370643b 100644 --- a/tests/compiler/dart2js/pretty_parameter_test.dart +++ b/tests/compiler/dart2js/pretty_parameter_test.dart @@ -99,10 +99,9 @@ main() { Expect.isTrue(regexp.hasMatch(generated)); regexp = new RegExp(r"a = 2;"); - Iterator matches = regexp.allMatches(generated).iterator(); - Expect.isTrue(matches.hasNext); - matches.next(); - Expect.isFalse(matches.hasNext); + Iterator matches = regexp.allMatches(generated).iterator; + Expect.isTrue(matches.moveNext()); + Expect.isFalse(matches.moveNext); generated = compile(PARAMETER_INIT, entry: 'foo'); regexp = new RegExp("var result = start;"); diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart index f6f87c5afd4..b3457a8e428 100644 --- a/tests/compiler/dart2js/resolver_test.dart +++ b/tests/compiler/dart2js/resolver_test.dart @@ -174,7 +174,7 @@ testThis() { FunctionExpression function = funElement.parseNode(compiler); visitor.visit(function.body); Map mapping = map(visitor); - List values = mapping.values; + List values = mapping.values.toList(); Expect.equals(0, mapping.length); Expect.equals(0, compiler.warnings.length); @@ -245,7 +245,7 @@ testLocalsThree() { MethodScope scope = visitor.scope; Expect.equals(0, scope.elements.length); Expect.equals(3, map(visitor).length); - List elements = map(visitor).values; + List elements = map(visitor).values.toList(); Expect.equals(elements[0], elements[1]); } @@ -258,7 +258,7 @@ testLocalsFour() { MethodScope scope = visitor.scope; Expect.equals(0, scope.elements.length); Expect.equals(2, map(visitor).length); - List elements = map(visitor).values; + List elements = map(visitor).values.toList(); Expect.notEquals(elements[0], elements[1]); } @@ -325,8 +325,8 @@ testFor() { // Check that we have the expected nodes. This test relies on the mapping // field to be a linked hash map (preserving insertion order). Expect.isTrue(map(visitor) is LinkedHashMap); - List nodes = map(visitor).keys; - List elements = map(visitor).values; + List nodes = map(visitor).keys.toList(); + List elements = map(visitor).values.toList(); // for (int i = 0; i < 10; i = i + 1) { i = 5; }; diff --git a/tests/compiler/dart2js/rewrite_better_user_test.dart b/tests/compiler/dart2js/rewrite_better_user_test.dart index 756c77f7612..6d1fbfe61d2 100644 --- a/tests/compiler/dart2js/rewrite_better_user_test.dart +++ b/tests/compiler/dart2js/rewrite_better_user_test.dart @@ -27,7 +27,7 @@ main() { main() { String generated = compileAll(TEST); RegExp regexp = new RegExp('foo\\\$0\\\$bailout'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; // We check that there is only one call to the bailout method. // One match for the call, one for the definition. diff --git a/tests/compiler/dart2js/type_guard_unuser_test.dart b/tests/compiler/dart2js/type_guard_unuser_test.dart index 199968f4b13..c4922ab8d11 100644 --- a/tests/compiler/dart2js/type_guard_unuser_test.dart +++ b/tests/compiler/dart2js/type_guard_unuser_test.dart @@ -42,13 +42,13 @@ foo(int a, int b) { main() { String generated = compile(TEST_ONE, entry: 'foo'); RegExp regexp = new RegExp(getIntTypeCheck(anyIdentifier)); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 0); Expect.isTrue(generated.contains(r'return a === true ? $.foo(2) : b;')); generated = compile(TEST_TWO, entry: 'foo'); regexp = new RegExp("foo\\(1\\)"); - matches = regexp.allMatches(generated).iterator(); + matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); generated = compile(TEST_THREE, entry: 'foo'); diff --git a/tests/compiler/dart2js/value_range_test.dart b/tests/compiler/dart2js/value_range_test.dart index 45b6328504e..5b2103ad353 100644 --- a/tests/compiler/dart2js/value_range_test.dart +++ b/tests/compiler/dart2js/value_range_test.dart @@ -40,7 +40,7 @@ ABOVE_ZERO, main(check) { // Make sure value is an int. var value = check ? 42 : 54; - var a = new List(value); + var a = new List.fixedLength(value); var sum = 0; for (int i = 0; i < value; i++) { sum += a[i]; @@ -68,7 +68,7 @@ KEPT, """ main() { - var a = new List(4); + var a = new List.fixedLength(4); return a[0]; } """, @@ -76,7 +76,7 @@ REMOVED, """ main() { - var a = new List(4); + var a = new List.fixedLength(4); return a.removeLast(); } """, @@ -84,7 +84,7 @@ REMOVED, """ main(value) { - var a = new List(value); + var a = new List.fixedLength(value); return a[value]; } """, @@ -92,7 +92,7 @@ KEPT, """ main(value) { - var a = new List(1024); + var a = new List.fixedLength(1024); return a[1023 & value]; } """, @@ -100,7 +100,7 @@ REMOVED, """ main(value) { - var a = new List(1024); + var a = new List.fixedLength(1024); return a[1024 & value]; } """, @@ -243,13 +243,13 @@ expect(String code, int kind) { case ONE_CHECK: RegExp regexp = new RegExp('ioore'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); break; case ONE_ZERO_CHECK: RegExp regexp = new RegExp('< 0'); - Iterator matches = regexp.allMatches(generated).iterator(); + Iterator matches = regexp.allMatches(generated).iterator; checkNumberOfMatches(matches, 1); break; } diff --git a/tests/compiler/dart2js_extra/for_in_test.dart b/tests/compiler/dart2js_extra/for_in_test.dart index d2f76ea94f7..0083115f1ab 100644 --- a/tests/compiler/dart2js_extra/for_in_test.dart +++ b/tests/compiler/dart2js_extra/for_in_test.dart @@ -23,10 +23,10 @@ testIterator(List expect, Iterable input) { Expect.equals(expect.length, i); } -class MyIterable implements Iterable { +class MyIterable extends Iterable { final List values; MyIterable(List values) : this.values = values; - Iterator iterator() { + Iterator get iterator { return new MyListIterator(values); } } @@ -34,9 +34,10 @@ class MyIterable implements Iterable { class MyListIterator implements Iterator { final List values; int index; - MyListIterator(List values) : this.values = values, index = 0; - bool get hasNext => index < values.length; - T next() => values[index++]; + MyListIterator(List values) : this.values = values, index = -1; + + bool moveNext() => ++index < values.length; + T current() => (0 <= index && index < length) ? values[index] : null; } void main() { diff --git a/tests/compiler/dart2js_extra/invalid_length_negative_test.dart b/tests/compiler/dart2js_extra/invalid_length_negative_test.dart index 98366536412..e990bd0719d 100644 --- a/tests/compiler/dart2js_extra/invalid_length_negative_test.dart +++ b/tests/compiler/dart2js_extra/invalid_length_negative_test.dart @@ -3,5 +3,5 @@ // BSD-style license that can be found in the LICENSE file. main() { - new List("foo"); + new List.fixedLength("foo"); } diff --git a/tests/compiler/dart2js_extra/list_factory_test.dart b/tests/compiler/dart2js_extra/list_factory_test.dart index e7745736f2d..1d7b940291d 100644 --- a/tests/compiler/dart2js_extra/list_factory_test.dart +++ b/tests/compiler/dart2js_extra/list_factory_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. main() { - var a = new List(4); + var a = new List.fixedLength(4); Expect.equals(4, a.length); a[0] = 42; a[1] = 43; diff --git a/tests/compiler/dart2js_extra/type_argument_factory_crash_test.dart b/tests/compiler/dart2js_extra/type_argument_factory_crash_test.dart index f6de717fb84..c357c2db1c4 100644 --- a/tests/compiler/dart2js_extra/type_argument_factory_crash_test.dart +++ b/tests/compiler/dart2js_extra/type_argument_factory_crash_test.dart @@ -12,6 +12,6 @@ void main() { Expect.isFalse(o is List); // Enable these two lines, the compiler doesn't crash. - // Expect.isTrue(o.keys is List); - // Expect.isFalse(o.keys is List); + // Expect.isTrue(o.keys is Iterable); + // Expect.isFalse(o.keys is Iterable); } diff --git a/tests/compiler/dart2js_extra/type_argument_factory_nocrash_test.dart b/tests/compiler/dart2js_extra/type_argument_factory_nocrash_test.dart index 607724f12af..3d1f10a039c 100644 --- a/tests/compiler/dart2js_extra/type_argument_factory_nocrash_test.dart +++ b/tests/compiler/dart2js_extra/type_argument_factory_nocrash_test.dart @@ -12,6 +12,6 @@ void main() { Expect.isFalse(o is List); // Enable these two lines, the compiler doesn't crash. - Expect.isTrue(o.keys is List); - Expect.isFalse(o.keys is List); + Expect.isTrue(o.keys is Iterable); + Expect.isFalse(o.keys is Iterable); } diff --git a/tests/corelib/collection_contains_test.dart b/tests/corelib/collection_contains_test.dart index 168855babe6..da96f5d98aa 100644 --- a/tests/corelib/collection_contains_test.dart +++ b/tests/corelib/collection_contains_test.dart @@ -12,7 +12,7 @@ test(list, notInList) { } Expect.isFalse(list.contains(notInList), "!$list.contains($notInList)"); } - List fixedList = new List(list.length); + List fixedList = new List.fixedLength(list.length); List growList = new List(); for (int i = 0; i < list.length; i++) { fixedList[i] = list[i]; diff --git a/tests/corelib/collection_test.dart b/tests/corelib/collection_test.dart index c1ea5b839f5..86d9e03d3f5 100644 --- a/tests/corelib/collection_test.dart +++ b/tests/corelib/collection_test.dart @@ -21,7 +21,7 @@ main() { new CollectionTest(TEST_ELEMENTS); // Fixed size list. - var fixedList = new List(TEST_ELEMENTS.length); + var fixedList = new List.fixedLength(TEST_ELEMENTS.length); for (int i = 0; i < TEST_ELEMENTS.length; i++) { fixedList[i] = TEST_ELEMENTS[i]; } diff --git a/tests/corelib/core_runtime_types_test.dart b/tests/corelib/core_runtime_types_test.dart index c40b781b767..b68a1ff00e5 100644 --- a/tests/corelib/core_runtime_types_test.dart +++ b/tests/corelib/core_runtime_types_test.dart @@ -221,15 +221,15 @@ class CoreRuntimeTypesTest { assertEquals(d.remove('c'), null); assertEquals(d.remove('b'), 2); - assertListEquals(d.keys, ['a']); - assertListEquals(d.values, [1]); + assertEquals(d.keys.single, 'a'); + assertEquals(d.values.single, 1); d['c'] = 3; d['f'] = 4; assertEquals(d.keys.length, 3); assertEquals(d.values.length, 3); - assertListContains(d.keys, ['a', 'c', 'f']); - assertListContains(d.values, [1, 3, 4]); + assertListContains(d.keys.toList(), ['a', 'c', 'f']); + assertListContains(d.values.toList(), [1, 3, 4]); var count = 0; d.forEach((key, value) { diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status index 3ad08b49db1..2fa93a15492 100644 --- a/tests/corelib/corelib.status +++ b/tests/corelib/corelib.status @@ -42,15 +42,14 @@ math_parse_double_test: Fail # Expect.equals(expected: <78187493520>, actual: <0 math_test: Fail # issue 3333 surrogate_pair_toUpper_test: Fail # Issue 6707 -# Bad test, assumes RegExp.allMatches returns a Collection. -reg_exp_all_matches_test: Fail, OK # NoSuchMethodError : method not found: 'forEach' - reg_exp4_test: Fail, OK # Expects exception from const constructor. big_integer_vm_test: Fail, OK # VM specific test. compare_to2_test: Fail, OK # Requires bigint support. string_base_vm_test: Fail, OK # VM specific test. +string_replace_func_test: Skip # Bug 6554 - doesn't terminate. + [ $compiler == dart2js && $runtime == none ] *: Fail, Pass # TODO(ahe): Triage these tests. @@ -68,3 +67,12 @@ compare_to2_test: Fail # inherited from VM null_test: Fail # inherited from VM unicode_test: Fail # inherited from VM +# Library changes +[ $compiler == none ] +future_test: Skip # Bug 6890 .TODO(ajohnsen): Fix this as part of library changes. + +[ $compiler == none || $compiler == dart2js || $compiler == dart2dart ] +map_keys2_test: Fail # Generic types aren't right. + +[ $compiler == dart2js ] +map_values2_test: Fail # Generic types aren't right diff --git a/tests/corelib/for_in_test.dart b/tests/corelib/for_in_test.dart index ea537273bc0..de51cc159ba 100644 --- a/tests/corelib/for_in_test.dart +++ b/tests/corelib/for_in_test.dart @@ -79,7 +79,7 @@ class ForInTest { static void testClosure() { Set set = getSmallSet(); - List closures = new List(set.length); + List closures = new List.fixedLength(set.length); int index = 0; for (var i in set) { closures[index++] = () => i; diff --git a/tests/corelib/future_test.dart b/tests/corelib/future_test.dart index f4e512c45d8..f1ae866c77e 100644 --- a/tests/corelib/future_test.dart +++ b/tests/corelib/future_test.dart @@ -2,15 +2,16 @@ // 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. +// TODO(ajohnsen): This test needs to be updated. +// Can Dart2JS on V8 somehow run it? + // Tests for Future.immediate +import 'dart:async'; +import 'dart:isolate'; testImmediate() { final future = new Future.immediate("42"); - Expect.isTrue(future.isComplete); - Expect.isTrue(future.hasValue); - var value = null; - future.then((x) => value = x); - Expect.equals("42", value); + future.then((x) => Expect.equals("42", x)); } // Tests for getters (value, exception, isComplete, isValue) @@ -18,10 +19,8 @@ testImmediate() { testNeverComplete() { final completer = new Completer(); final future = completer.future; - Expect.isFalse(future.isComplete); - Expect.isFalse(future.hasValue); - Expect.throws(() { future.value; }); - Expect.throws(() { future.exception; }); + future.then((v) => Except.fails("Value not expected")); + future.catchError((e) => Except.fails("Value not expected")); } testComplete() { @@ -30,123 +29,7 @@ testComplete() { completer.complete(3); - Expect.isTrue(future.isComplete); - Expect.isTrue(future.hasValue); - Expect.equals(3, future.value); - Expect.isNull(future.exception); -} - -// Tests for [onComplete] - -testCompleteWithCompleteHandlerBeforeComplete() { - final completer = new Completer(); - final future = completer.future; - - int before; - future.onComplete((f) { - Expect.equals(future, f); - Expect.isTrue(f.isComplete); - Expect.isTrue(f.hasValue); - before = f.value; - }); - Expect.throws(() => future.value); - Expect.isNull(before); - completer.complete(3); - - Expect.equals(3, future.value); - Expect.equals(3, before); -} - -testExceptionWithCompleteHandlerBeforeComplete() { - final completer = new Completer(); - final future = completer.future; - final exception = new Exception(); - - var err; - future.onComplete((f) { - Expect.equals(future, f); - Expect.isTrue(f.isComplete); - Expect.isFalse(f.hasValue); - err = f.exception; - }); - Expect.throws(() => future.exception); - Expect.isNull(err); - completer.completeException(exception); - Expect.equals(exception, future.exception); - Expect.equals(exception, err); - Expect.throws(() => future.value, (e) => e.source == exception); -} - -testCompleteWithCompleteHandlerAfterComplete() { - final completer = new Completer(); - final future = completer.future; - - int after; - completer.complete(3); - future.onComplete((f) { - Expect.equals(future, f); - Expect.isTrue(f.isComplete); - Expect.isTrue(f.hasValue); - after = f.value; - }); - Expect.equals(3, future.value); - Expect.equals(3, after); -} - -testExceptionWithCompleteHandlerAfterComplete() { - final completer = new Completer(); - final future = completer.future; - final exception = new Exception(); - - var err; - completer.completeException(exception); - future.onComplete((f) { - Expect.equals(future, f); - Expect.isTrue(f.isComplete); - Expect.isFalse(f.hasValue); - err = f.exception; - }); - Expect.equals(exception, future.exception); - Expect.equals(exception, err); - Expect.throws(() => future.value, (e) => e.source == exception); -} - -testCompleteWithManyCompleteHandlers() { - final completer = new Completer(); - final future = completer.future; - int before; - int after1; - int after2; - - future.onComplete((f) { before = f.value; }); - completer.complete(3); - future.onComplete((f) { after1 = f.value; }); - future.onComplete((f) { after2 = f.value; }); - - Expect.equals(3, future.value); - Expect.equals(3, before); - Expect.equals(3, after1); - Expect.equals(3, after2); -} - -testExceptionWithManyCompleteHandlers() { - final completer = new Completer(); - final future = completer.future; - final exception = new Exception(); - var before; - var after1; - var after2; - - future.onComplete((f) { before = f.exception; }); - completer.completeException(exception); - future.onComplete((f) { after1 = f.exception; }); - future.onComplete((f) { after2 = f.exception; }); - - Expect.equals(exception, future.exception); - Expect.equals(exception, before); - Expect.equals(exception, after1); - Expect.equals(exception, after2); - Expect.throws(() => future.value, (e) => e.source == exception); + future.then((v) => Expect.equals(3, v)); } // Tests for [then] @@ -157,11 +40,9 @@ testCompleteWithSuccessHandlerBeforeComplete() { int before; future.then((int v) { before = v; }); - Expect.throws(() { future.value; }); Expect.isNull(before); completer.complete(3); - Expect.equals(3, future.value); Expect.equals(3, before); } @@ -171,12 +52,10 @@ testCompleteWithSuccessHandlerAfterComplete() { int after; completer.complete(3); - Expect.equals(3, future.value); Expect.isNull(after); future.then((int v) { after = v; }); - Expect.equals(3, future.value); Expect.equals(3, after); } @@ -192,7 +71,6 @@ testCompleteManySuccessHandlers() { future.then((int v) { after1 = v; }); future.then((int v) { after2 = v; }); - Expect.equals(3, future.value); Expect.equals(3, before); Expect.equals(3, after1); Expect.equals(3, after2); @@ -204,10 +82,10 @@ testException() { final completer = new Completer(); final future = completer.future; final ex = new Exception(); - future.then((_) {}); // exception is thrown if we plan to use the value - Expect.throws( - () { completer.completeException(ex); }, - (e) => e.source == ex); +// future.catchError((e) => print("got error"));//Expect.equals(e, ex)); + future.then((v) {print(v);}) + .catchError((e) => Expect.equals(e.error, ex)); + completer.completeError(ex); } testExceptionNoSuccessListeners() { @@ -223,8 +101,8 @@ testExceptionHandler() { final ex = new Exception(); var ex2; - future.handleException((e) { ex2 = e; return true; }); - completer.completeException(ex); + future.catchError((e) { ex2 = e.error; }); + completer.completeError(ex); Expect.equals(ex, ex2); } @@ -234,9 +112,10 @@ testExceptionHandlerReturnsTrue() { final ex = new Exception(); bool reached = false; - future.handleException((e) { return true; }); - future.handleException((e) { reached = true; return false; }); // overshadowed - completer.completeException(ex); + future.catchError((e) { }); + future.catchError((e) { reached = true; }, test: (e) => false) + .catchError((e) {}); + completer.completeError(ex); Expect.isFalse(reached); } @@ -246,9 +125,9 @@ testExceptionHandlerReturnsTrue2() { final ex = new Exception(); bool reached = false; - future.handleException((e) { return false; }); - future.handleException((e) { reached = true; return true; }); - completer.completeException(ex); + future.catchError((e) { }, test: (e) => false) + .catchError((e) { reached = true; }); + completer.completeError(ex); Expect.isTrue(reached); } @@ -258,13 +137,15 @@ testExceptionHandlerReturnsFalse() { final ex = new Exception(); bool reached = false; - future.then((_) {}); // ensure exception is thrown... - future.handleException((e) { return false; }); - future.handleException((e) { reached = true; return false; }); // overshadowed - Expect.throws( - () { completer.completeException(ex); }, - (e) => e.source == ex); - Expect.isTrue(reached); + + future.catchError((e) { }); + + future.catchError((e) { reached = true; }, test: (e) => false) + .catchError((e) { }); + + completer.completeError(ex); + + Expect.isFalse(reached); } testExceptionHandlerReturnsFalse2() { @@ -331,7 +212,7 @@ testCallStackReturnsCallstackPassedToCompleteException() { testCallStackIsCapturedIfTransformCallbackThrows() { final completer = new Completer(); - final transformed = completer.future.transform((_) { + final transformed = completer.future.then((_) { throw 'whoops!'; }); @@ -428,7 +309,7 @@ testExceptionWithCompletionAndSuccessAndExceptionHandlers() { testTransformSuccess() { final completer = new Completer(); - final transformedFuture = completer.future.transform((x) => "** $x **"); + final transformedFuture = completer.future.then((x) => "** $x **"); Expect.isFalse(transformedFuture.isComplete); completer.complete("42"); Expect.equals("** 42 **", transformedFuture.value); @@ -437,7 +318,7 @@ testTransformSuccess() { testTransformFutureFails() { final completer = new Completer(); final error = new Exception("Oh no!"); - final transformedFuture = completer.future.transform((x) { + final transformedFuture = completer.future.then((x) { Expect.fail("transformer shouldn't be called"); }); Expect.isFalse(transformedFuture.isComplete); @@ -448,7 +329,7 @@ testTransformFutureFails() { testTransformTransformerFails() { final completer = new Completer(); final error = new Exception("Oh no!"); - final transformedFuture = completer.future.transform((x) { throw error; }); + final transformedFuture = completer.future.then((x) { throw error; }); Expect.isFalse(transformedFuture.isComplete); transformedFuture.then((v) => null); Expect.throws(() => completer.complete("42"), (e) => e.source == error); @@ -584,8 +465,8 @@ testExceptionTravelsAlongBothBranches() { var results = []; var completer = new Completer(); - var branch1 = completer.future.transform((_) => null); - var branch2 = completer.future.transform((_) => null); + var branch1 = completer.future.then((_) => null); + var branch2 = completer.future.then((_) => null); branch1.handleException((e) { results.add(1); @@ -607,8 +488,8 @@ testExceptionTravelsAlongBothBranchesAfterComplete() { var completer = new Completer(); completer.completeException("error"); - var branch1 = completer.future.transform((_) => null); - var branch2 = completer.future.transform((_) => null); + var branch1 = completer.future.then((_) => null); + var branch2 = completer.future.then((_) => null); branch1.handleException((e) { results.add(1); @@ -627,7 +508,7 @@ testExceptionIsHandledInBaseAndBranch() { var results = []; var completer = new Completer(); - var branch = completer.future.transform((_) => null); + var branch = completer.future.then((_) => null); completer.future.handleException((e) { results.add("base"); @@ -649,7 +530,7 @@ testExceptionIsHandledInBaseAndBranchAfterComplete() { var completer = new Completer(); completer.completeException("error"); - var branch = completer.future.transform((_) => null); + var branch = completer.future.then((_) => null); completer.future.handleException((e) { results.add("base"); @@ -665,15 +546,10 @@ testExceptionIsHandledInBaseAndBranchAfterComplete() { } main() { +// /* testImmediate(); testNeverComplete(); testComplete(); - testCompleteWithCompleteHandlerBeforeComplete(); - testExceptionWithCompleteHandlerBeforeComplete(); - testCompleteWithCompleteHandlerAfterComplete(); - testExceptionWithCompleteHandlerAfterComplete(); - testCompleteWithManyCompleteHandlers(); - testExceptionWithManyCompleteHandlers(); testCompleteWithSuccessHandlerBeforeComplete(); testCompleteWithSuccessHandlerAfterComplete(); testCompleteManySuccessHandlers(); @@ -682,6 +558,10 @@ main() { testExceptionHandlerReturnsTrue(); testExceptionHandlerReturnsTrue2(); testExceptionHandlerReturnsFalse(); +// */ + /* + */ + /* testExceptionHandlerReturnsFalse2(); testExceptionHandlerAfterCompleteThenNotCalled(); testExceptionHandlerAfterCompleteReturnsFalseThenThrows(); @@ -709,4 +589,5 @@ main() { testExceptionTravelsAlongBothBranchesAfterComplete(); testExceptionIsHandledInBaseAndBranch(); testExceptionIsHandledInBaseAndBranchAfterComplete(); + */ } diff --git a/tests/corelib/futures_test.dart b/tests/corelib/futures_test.dart index 70a54bfbb44..ec68075d00d 100644 --- a/tests/corelib/futures_test.dart +++ b/tests/corelib/futures_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. library futures_test; +import 'dart:async'; import 'dart:isolate'; Future testWaitEmpty() { @@ -38,7 +39,7 @@ Future testForEach() { return Futures.forEach([1, 2, 3, 4, 5], (n) { seen.add(n); return new Future.immediate(null); - }).transform((_) => Expect.listEquals([1, 2, 3, 4, 5], seen)); + }).then((_) => Expect.listEquals([1, 2, 3, 4, 5], seen)); } Future testForEachWithException() { @@ -47,10 +48,10 @@ Future testForEachWithException() { if (n == 4) throw 'correct exception'; seen.add(n); return new Future.immediate(null); - }).transform((_) { + }).then((_) { throw 'incorrect exception'; - }).transformException((e) { - Expect.equals('correct exception', e); + }).catchError((e) { + Expect.equals('correct exception', e.error); }); } @@ -63,7 +64,7 @@ main() { futures.add(testForEachEmpty()); futures.add(testForEach()); - // Use a receive port for blocking the test. + // Use a receive port for blocking the test. // Note that if the test fails, the program will not end. ReceivePort port = new ReceivePort(); Futures.wait(futures).then((List list) { diff --git a/tests/corelib/has_next_iterator_test.dart b/tests/corelib/has_next_iterator_test.dart new file mode 100644 index 00000000000..803bfd03619 --- /dev/null +++ b/tests/corelib/has_next_iterator_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2012, 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. + +main() { + var it = new HasNextIterator([].iterator); + Expect.isFalse(it.hasNext); + Expect.isFalse(it.hasNext); + Expect.throws(() => it.next(), (e) => e is StateError); + Expect.isFalse(it.hasNext); + + it = new HasNextIterator([1].iterator); + Expect.isTrue(it.hasNext); + Expect.isTrue(it.hasNext); + Expect.equals(1, it.next()); + Expect.isFalse(it.hasNext); + Expect.isFalse(it.hasNext); + Expect.throws(() => it.next(), (e) => e is StateError); + Expect.isFalse(it.hasNext); + + it = new HasNextIterator([1, 2].iterator); + Expect.isTrue(it.hasNext); + Expect.isTrue(it.hasNext); + Expect.equals(1, it.next()); + Expect.isTrue(it.hasNext); + Expect.isTrue(it.hasNext); + Expect.equals(2, it.next()); + Expect.isFalse(it.hasNext); + Expect.isFalse(it.hasNext); + Expect.throws(() => it.next(), (e) => e is StateError); + Expect.isFalse(it.hasNext); +} diff --git a/tests/corelib/indexed_list_access_test.dart b/tests/corelib/indexed_list_access_test.dart index 2feab1e4402..791e961131d 100644 --- a/tests/corelib/indexed_list_access_test.dart +++ b/tests/corelib/indexed_list_access_test.dart @@ -6,7 +6,7 @@ // is not int. main() { - checkList(new List(10)); + checkList(new List.fixedLength(10)); var growable = new List(); growable.add(1); growable.add(1); diff --git a/tests/corelib/int_parse_radix_test.dart b/tests/corelib/int_parse_radix_test.dart new file mode 100644 index 00000000000..a59ee600875 --- /dev/null +++ b/tests/corelib/int_parse_radix_test.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2012, 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. + +void main() { + bool checkedMode = false; + assert(checkedMode = true); + + for (int i = 0; i < 36 * 36 + 1; i++) { + for (int r = 2; r <= 36; r++) { + String radixString = i.toRadixString(r); + Expect.equals(i, int.parse(radixString, radix: r), ""); + Expect.equals(i, int.parse(" $radixString", radix: r), ""); + Expect.equals(i, int.parse("$radixString ", radix: r), ""); + Expect.equals(i, int.parse(" $radixString ", radix: r), ""); + Expect.equals(i, int.parse("+$radixString", radix: r), ""); + Expect.equals(i, int.parse(" +$radixString", radix: r), ""); + Expect.equals(i, int.parse("+$radixString ", radix: r), ""); + Expect.equals(i, int.parse(" +$radixString ", radix: r), ""); + Expect.equals(-i, int.parse("-$radixString", radix: r), ""); + Expect.equals(-i, int.parse(" -$radixString", radix: r), ""); + Expect.equals(-i, int.parse("-$radixString ", radix: r), ""); + Expect.equals(-i, int.parse(" -$radixString ", radix: r), ""); + } + } + // Allow both upper- and lower-case letters. + Expect.equals(0xABCD, int.parse("ABCD", radix: 16)); + Expect.equals(0xABCD, int.parse("abcd", radix: 16)); + Expect.equals(15628859, int.parse("09azAZ", radix: 36)); + + // Allow whitespace before and after the number. + Expect.equals(1, int.parse(" 1", radix: 2)); + Expect.equals(1, int.parse("1 ", radix: 2)); + Expect.equals(1, int.parse(" 1 ", radix: 2)); + Expect.equals(1, int.parse("\n1", radix: 2)); + Expect.equals(1, int.parse("1\n", radix: 2)); + Expect.equals(1, int.parse("\n1\n", radix: 2)); + Expect.equals(1, int.parse("+1", radix: 2)); + + void testFails(String source, int radix) { + Expect.throws(() { throw int.parse(source, radix: radix, + onError: (s) { throw "FAIL"; }); }, + (e) => e == "FAIL", + "$source/$radix"); + Expect.equals(-999, int.parse(source, radix: radix, onError: (s) => -999)); + } + for (int i = 2; i < 36; i++) { + testFails(i.toRadixString(36), i); + } + testFails("", 2); + testFails("0x10", 16); // No 0x specially allowed. + testFails("+ 1", 2); // No space between sign and digits. + testFails("- 1", 2); // No space between sign and digits. + + testBadTypes(var source, var radix) { + if (!checkedMode) { + // No promises on what error is thrown if the type doesn't match. + // Likely either ArgumentError or NoSuchMethodError. + Expect.throws(() => int.parse(source, radix: radix, onError: (s) => 0)); + return; + } + // In checked mode, it's always a TypeError. + Expect.throws(() => int.parse(source, radix: radix, onError: (s) => 0), + (e) => e is TypeError); + } + + testBadTypes(9, 10); + testBadTypes(true, 10); + testBadTypes("0", true); + testBadTypes("0", "10"); + + testBadArguments(String source, int radix) { + // If the types match, it should be an ArgumentError of some sort. + Expect.throws(() => int.parse(source, radix: radix, onError: (s) => 0), + (e) => e is ArgumentError); + } + + testBadArguments("0", -1); + testBadArguments("0", 0); + testBadArguments("0", 1); + testBadArguments("0", 37); + + // If handleError isn't an unary function, and it's called, it also throws + // (either TypeError in checked mode, or some failure in unchecked mode). + Expect.throws(() => int.parse("9", radix: 8, onError: "not a function")); + Expect.throws(() => int.parse("9", radix: 8, onError: () => 42)); + Expect.throws(() => int.parse("9", radix: 8, onError: (v1, v2) => 42)); +} diff --git a/tests/corelib/iterable_element_at_test.dart b/tests/corelib/iterable_element_at_test.dart new file mode 100644 index 00000000000..2dd6920cb40 --- /dev/null +++ b/tests/corelib/iterable_element_at_test.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5, 6]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Expect.equals(1, list1.elementAt(0)); + Expect.equals(2, list1.elementAt(1)); + Expect.equals(3, list1.elementAt(2)); + Expect.throws(() => list1.elementAt("2"), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => list1.elementAt(-1), (e) => e is ArgumentError); + Expect.throws(() => list1.elementAt(3), (e) => e is RangeError); + + Expect.equals(4, list2.elementAt(0)); + Expect.equals(5, list2.elementAt(1)); + Expect.equals(6, list2.elementAt(2)); + Expect.throws(() => list2.elementAt("2"), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => list2.elementAt(-1), (e) => e is ArgumentError); + Expect.throws(() => list2.elementAt(3), (e) => e is RangeError); + + Expect.isTrue(set1.contains(set1.elementAt(0))); + Expect.isTrue(set1.contains(set1.elementAt(1))); + Expect.isTrue(set1.contains(set1.elementAt(2))); + Expect.throws(() => set1.elementAt(-1), (e) => e is ArgumentError); + Expect.throws(() => set1.elementAt(3), (e) => e is RangeError); + + Expect.throws(() => set2.elementAt("2"), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => set2.elementAt(-1), (e) => e is ArgumentError); + Expect.throws(() => set2.elementAt(0), (e) => e is RangeError); + Expect.throws(() => set2.elementAt(1), (e) => e is RangeError); +} diff --git a/tests/corelib/iterable_first_matching_test.dart b/tests/corelib/iterable_first_matching_test.dart new file mode 100644 index 00000000000..e5429127007 --- /dev/null +++ b/tests/corelib/iterable_first_matching_test.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Expect.equals(2, list1.firstMatching((x) => x.isEven)); + Expect.equals(1, list1.firstMatching((x) => x.isOdd)); + Expect.throws(() => list1.firstMatching((x) => x > 3), + (e) => e is StateError); + Expect.equals(null, list1.firstMatching((x) => x > 3, orElse: () => null)); + Expect.equals(499, list1.firstMatching((x) => x > 3, orElse: () => 499)); + + Expect.equals(4, list2.firstMatching((x) => x.isEven)); + Expect.equals(5, list2.firstMatching((x) => x.isOdd)); + Expect.throws(() => list2.firstMatching((x) => x == 0), + (e) => e is StateError); + Expect.equals(null, list2.firstMatching((x) => false, orElse: () => null)); + Expect.equals(499, list2.firstMatching((x) => false, orElse: () => 499)); + + Expect.throws(() => list3.firstMatching((x) => x == 0), + (e) => e is StateError); + Expect.throws(() => list3.firstMatching((x) => true), (e) => e is StateError); + Expect.equals(null, list3.firstMatching((x) => true, orElse: () => null)); + Expect.equals("str", list3.firstMatching((x) => false, orElse: () => "str")); + + Expect.equals(12, set1.firstMatching((x) => x.isEven)); + var odd = set1.firstMatching((x) => x.isOdd); + Expect.isTrue(odd == 11 || odd == 13); + Expect.throws(() => set1.firstMatching((x) => false), (e) => e is StateError); + Expect.equals(null, set1.firstMatching((x) => false, orElse: () => null)); + Expect.equals(499, set1.firstMatching((x) => false, orElse: () => 499)); + + Expect.throws(() => set2.firstMatching((x) => false), (e) => e is StateError); + Expect.throws(() => set2.firstMatching((x) => true), (e) => e is StateError); + Expect.equals(null, set2.firstMatching((x) => true, orElse: () => null)); + Expect.equals(499, set2.firstMatching((x) => false, orElse: () => 499)); +} diff --git a/tests/corelib/iterable_first_test.dart b/tests/corelib/iterable_first_test.dart new file mode 100644 index 00000000000..44945a526e5 --- /dev/null +++ b/tests/corelib/iterable_first_test.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Expect.equals(1, list1.first); + Expect.equals(4, list2.first); + Expect.throws(() => list3.first, (e) => e is StateError); + + Expect.isTrue(set1.contains(set1.first)); + + Expect.throws(() => set2.first, (e) => e is StateError); +} diff --git a/tests/corelib/iterable_join_test.dart b/tests/corelib/iterable_join_test.dart new file mode 100644 index 00000000000..a1df9b7439f --- /dev/null +++ b/tests/corelib/iterable_join_test.dart @@ -0,0 +1,63 @@ +// Copyright (c) 2012, 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. + +class IC { + int count = 0; + String toString() => "${count++}"; +} + +testJoin(String expect, Iterable iterable, [String separator]) { + Expect.equals(expect, iterable.join(separator)); +} + +testCollections() { + testJoin("", [], ","); + testJoin("", [], ""); + testJoin("", []); + testJoin("", new Set(), ","); + testJoin("", new Set(), ""); + testJoin("", new Set()); + + testJoin("42", [42], ","); + testJoin("42", [42], ""); + testJoin("42", [42]); + testJoin("42", new Set()..add(42), ","); + testJoin("42", new Set()..add(42), ""); + testJoin("42", new Set()..add(42)); + + testJoin("a,b,c,d", ["a", "b", "c", "d"], ","); + testJoin("abcd", ["a", "b", "c", "d"], ""); + testJoin("abcd", ["a", "b", "c", "d"]); + testJoin("null,b,c,d", [null,"b","c","d"], ","); + testJoin("1,2,3,4", [1, 2, 3, 4], ","); + var ic = new IC(); + testJoin("0,1,2,3", [ic, ic, ic, ic], ","); + + var set = new Set()..add(1)..add(2)..add(3); + var perm = new Set()..add("123")..add("132")..add("213") + ..add("231")..add("312")..add("321"); + var setString = set.join(); + Expect.isTrue(perm.contains(setString), "set: $setString"); + + void testArray(array) { + testJoin("1,3,5,7,9", array.where((i) => i.isOdd), ","); + testJoin("0,2,4,6,8,10,12,14,16,18", array.mappedBy((i) => i * 2), ","); + testJoin("5,6,7,8,9", array.skip(5), ","); + testJoin("5,6,7,8,9", array.skipWhile((i) => i < 5), ","); + testJoin("0,1,2,3,4", array.take(5), ","); + testJoin("0,1,2,3,4", array.takeWhile((i) => i < 5), ","); + } + testArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + var fixedArray = new List.fixedLength(10); + for (int i = 0; i < 10; i++) { + fixedArray[i] = i; + } + testArray(fixedArray); + testArray(const [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +} + +main() { + testCollections(); + // TODO(lrn): test scalar lists. +} diff --git a/tests/corelib/iterable_last_matching_test.dart b/tests/corelib/iterable_last_matching_test.dart new file mode 100644 index 00000000000..bf6d20dd098 --- /dev/null +++ b/tests/corelib/iterable_last_matching_test.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5, 6]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Expect.equals(2, list1.lastMatching((x) => x.isEven)); + Expect.equals(3, list1.lastMatching((x) => x.isOdd)); + Expect.throws(() => list1.lastMatching((x) => x > 3), + (e) => e is StateError); + Expect.equals(null, list1.lastMatching((x) => x > 3, orElse: () => null)); + Expect.equals(499, list1.lastMatching((x) => x > 3, orElse: () => 499)); + + Expect.equals(6, list2.lastMatching((x) => x.isEven)); + Expect.equals(5, list2.lastMatching((x) => x.isOdd)); + Expect.throws(() => list2.lastMatching((x) => x == 0), + (e) => e is StateError); + Expect.equals(null, list2.lastMatching((x) => false, orElse: () => null)); + Expect.equals(499, list2.lastMatching((x) => false, orElse: () => 499)); + + Expect.throws(() => list3.lastMatching((x) => x == 0), + (e) => e is StateError); + Expect.throws(() => list3.lastMatching((x) => true), (e) => e is StateError); + Expect.equals(null, list3.lastMatching((x) => true, orElse: () => null)); + Expect.equals("str", list3.lastMatching((x) => false, orElse: () => "str")); + + Expect.equals(12, set1.lastMatching((x) => x.isEven)); + var odd = set1.lastMatching((x) => x.isOdd); + Expect.isTrue(odd == 11 || odd == 13); + Expect.throws(() => set1.lastMatching((x) => false), (e) => e is StateError); + Expect.equals(null, set1.lastMatching((x) => false, orElse: () => null)); + Expect.equals(499, set1.lastMatching((x) => false, orElse: () => 499)); + + Expect.throws(() => set2.lastMatching((x) => false), (e) => e is StateError); + Expect.throws(() => set2.lastMatching((x) => true), (e) => e is StateError); + Expect.equals(null, set2.lastMatching((x) => true, orElse: () => null)); + Expect.equals(499, set2.lastMatching((x) => false, orElse: () => 499)); +} diff --git a/tests/corelib/iterable_last_test.dart b/tests/corelib/iterable_last_test.dart new file mode 100644 index 00000000000..24539bf2c40 --- /dev/null +++ b/tests/corelib/iterable_last_test.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Expect.equals(3, list1.last); + Expect.equals(5, list2.last); + Expect.throws(() => list3.last, (e) => e is StateError); + + Expect.isTrue(set1.contains(set1.last)); + + Expect.throws(() => set2.last, (e) => e is StateError); +} diff --git a/tests/corelib/iterable_length_test.dart b/tests/corelib/iterable_length_test.dart new file mode 100644 index 00000000000..8dd6cdaf9ee --- /dev/null +++ b/tests/corelib/iterable_length_test.dart @@ -0,0 +1,41 @@ +// Copyright (c) 2012, 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. + +class A extends Iterable { + int count; + A(this.count); + + Iterator get iterator { + return new AIterator(count); + } +} + +class AIterator implements Iterator { + int _count; + int _current; + + AIterator(this._count); + + bool moveNext() { + if (_count > 0) { + _current = _count; + _count--; + return true; + } + _current = null; + return false; + } + + get current => _current; +} + +main() { + var a = new A(10); + Expect.equals(10, a.length); + a = new A(0); + Expect.equals(0, a.length); + a = new A(5); + Expect.equals(5, a.mappedBy((e) => e + 1).length); + Expect.equals(3, a.where((e) => e >= 3).length); +} diff --git a/tests/corelib/iterable_min_max_test.dart b/tests/corelib/iterable_min_max_test.dart new file mode 100644 index 00000000000..0a64a01a7a1 --- /dev/null +++ b/tests/corelib/iterable_min_max_test.dart @@ -0,0 +1,78 @@ +// Copyright (c) 2012, 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. + +import "dart:collection"; + +class C { + final x; + const C(this.x); + int get hashCode => x.hashCode; + bool operator==(var other) => other is C && x == other.x; +} + +const inf = double.INFINITY; + +var intList = const [0, 1, -1, -5, 5, -1000, 1000, -7, 7]; +var doubleList = const [-0.0, 0.0, -1.0, 1.0, -1000.0, 1000.0, -inf, inf]; +var stringList = const ["bbb", "bba", "bab", "abb", "bbc", "bcb", "cbb", "bb"]; +var cList = const [const C(5), const C(3), const C(8), + const C(0), const C(10), const C(6)]; +int compareC(C a, C b) => a.x.compareTo(b.x); + + +testMinMax(iterable, min, max) { + Expect.equals(min, iterable.min()); + Expect.equals(min, iterable.min(Comparable.compare)); + Expect.equals(min, Collections.min(iterable)); + Expect.equals(min, Collections.min(iterable, Comparable.compare)); + Expect.equals(max, iterable.min((a, b) => Comparable.compare(b, a))); + + Expect.equals(max, iterable.max()); + Expect.equals(max, iterable.max(Comparable.compare)); + Expect.equals(max, Collections.max(iterable)); + Expect.equals(max, Collections.max(iterable, Comparable.compare)); + Expect.equals(min, iterable.max((a, b) => Comparable.compare(b, a))); +} + + +main() { + testMinMax(const [], null, null); + testMinMax([], null, null); + testMinMax(new Set(), null, null); + + testMinMax(intList, -1000, 1000); // Const list. + testMinMax(new List.from(intList), -1000, 1000); // Non-const list. + testMinMax(new Set.from(intList), -1000, 1000); // Set. + + testMinMax(doubleList, -inf, inf); + testMinMax(new List.from(doubleList), -inf, inf); + testMinMax(new Set.from(doubleList), -inf, inf); + + testMinMax(stringList, "abb", "cbb"); + testMinMax(new List.from(stringList), "abb", "cbb"); + testMinMax(new Set.from(stringList), "abb", "cbb"); + + // Objects that are not Comparable. + Expect.equals(const C(0), cList.min(compareC)); + Expect.equals(const C(0), Collections.min(cList, compareC)); + Expect.equals(const C(0), new List.from(cList).min(compareC)); + Expect.equals(const C(0), Collections.min(new List.from(cList), compareC)); + Expect.equals(const C(0), new Set.from(cList).min(compareC)); + Expect.equals(const C(0), Collections.min(new Set.from(cList), compareC)); + + Expect.equals(const C(10), cList.max(compareC)); + Expect.equals(const C(10), Collections.max(cList, compareC)); + Expect.equals(const C(10), new List.from(cList).max(compareC)); + Expect.equals(const C(10), Collections.max(new List.from(cList), compareC)); + Expect.equals(const C(10), new Set.from(cList).max(compareC)); + Expect.equals(const C(10), Collections.max(new Set.from(cList), compareC)); + + bool checkedMode = false; + assert(checkedMode = true); + Expect.throws(cList.min, (e) => checkedMode ? e is TypeError + : e is NoSuchMethodError); + Expect.throws(cList.max, (e) => checkedMode ? e is TypeError + : e is NoSuchMethodError); +} + diff --git a/tests/corelib/iterable_single_matching_test.dart b/tests/corelib/iterable_single_matching_test.dart new file mode 100644 index 00000000000..d51d6ee6659 --- /dev/null +++ b/tests/corelib/iterable_single_matching_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5, 6]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Expect.equals(2, list1.singleMatching((x) => x.isEven)); + Expect.equals(3, list1.singleMatching((x) => x == 3)); + Expect.throws(() => list1.singleMatching((x) => x.isOdd), + (e) => e is StateError); + + Expect.equals(6, list2.singleMatching((x) => x == 6)); + Expect.equals(5, list2.singleMatching((x) => x.isOdd)); + Expect.throws(() => list2.singleMatching((x) => x.isEven), + (e) => e is StateError); + + Expect.throws(() => list3.singleMatching((x) => x == 0), + (e) => e is StateError); + + Expect.equals(12, set1.singleMatching((x) => x.isEven)); + Expect.equals(11, set1.singleMatching((x) => x == 11)); + Expect.throws(() => set1.singleMatching((x) => x.isOdd)); + + Expect.throws(() => set2.singleMatching((x) => true), (e) => e is StateError); +} diff --git a/tests/corelib/iterable_single_test.dart b/tests/corelib/iterable_single_test.dart new file mode 100644 index 00000000000..9c3b09a728d --- /dev/null +++ b/tests/corelib/iterable_single_test.dart @@ -0,0 +1,31 @@ +// Copyright (c) 2012, 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. + +main() { + List list1a = [1]; + List list1b = [1, 2, 3]; + List list1c = []; + List list2a = const [5]; + List list2b = const [4, 5]; + List list2c = const []; + Set set1 = new Set(); + set1..add(22); + Set set2 = new Set(); + set2..add(11) + ..add(12) + ..add(13); + Set set3 = new Set(); + + Expect.equals(1, list1a.single); + Expect.throws(() => list1b.single, (e) => e is StateError); + Expect.throws(() => list1c.single, (e) => e is StateError); + + Expect.equals(5, list2a.single); + Expect.throws(() => list2b.single, (e) => e is StateError); + Expect.throws(() => list2c.single, (e) => e is StateError); + + Expect.equals(22, set1.single); + Expect.throws(() => set2.single, (e) => e is StateError); + Expect.throws(() => set3.single, (e) => e is StateError); +} diff --git a/tests/corelib/iterable_skip_test.dart b/tests/corelib/iterable_skip_test.dart new file mode 100644 index 00000000000..63e6ef421bd --- /dev/null +++ b/tests/corelib/iterable_skip_test.dart @@ -0,0 +1,206 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Iterable skip0 = list1.skip(0); + Iterator it = skip0.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skip1 = list1.skip(1); + it = skip1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skip2 = list1.skip(2); + it = skip2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skip3 = list1.skip(3); + it = skip3.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skip4 = list1.skip(4); + it = skip4.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip0 = list1.skip(0); + skip1 = skip0.skip(1); + skip2 = skip1.skip(1); + skip3 = skip2.skip(1); + skip4 = skip3.skip(1); + it = skip0.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = skip1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = skip2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = skip3.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = skip4.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip0 = list2.skip(0); + it = skip0.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip1 = list2.skip(1); + it = skip1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip2 = list2.skip(2); + it = skip2.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip3 = list2.skip(3); + it = skip3.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skip02 = list3.skip(0); + Iterator it2 = skip02.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + Iterable skip12 = list3.skip(1); + it2 = skip12.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + skip0 = set1.skip(0); + List copied = skip0.toList(); + Expect.equals(3, copied.length); + Expect.isTrue(set1.contains(copied[0])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(set1.contains(copied[2])); + Expect.isTrue(copied[0] != copied[1]); + Expect.isTrue(copied[0] != copied[2]); + Expect.isTrue(copied[1] != copied[2]); + it = skip0.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip1 = set1.skip(1); + copied = skip1.toList(); + Expect.equals(2, copied.length); + Expect.isTrue(set1.contains(copied[0])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(copied[0] != copied[1]); + it = skip1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip2 = set1.skip(2); + copied = skip2.toList(); + Expect.equals(1, copied.length); + Expect.isTrue(set1.contains(copied[0])); + it = skip2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip3 = set1.skip(3); + it = skip3.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip4 = set1.skip(4); + it = skip4.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip0 = set2.skip(0); + it = skip0.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skip1 = set2.skip(1); + it = skip1.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); +} diff --git a/tests/corelib/iterable_skip_while_test.dart b/tests/corelib/iterable_skip_while_test.dart new file mode 100644 index 00000000000..4ddc5fa03e1 --- /dev/null +++ b/tests/corelib/iterable_skip_while_test.dart @@ -0,0 +1,146 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Iterable skipWhileTrue = list1.skipWhile((x) => true); + Iterator it = skipWhileTrue.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skipWhileOdd = list1.skipWhile((x) => x.isOdd); + it = skipWhileOdd.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skipWhileLessThan3 = list1.skipWhile((x) => x < 3); + it = skipWhileLessThan3.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skipWhileFalse = list1.skipWhile((x) => false); + it = skipWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skipWhileEven = list1.skipWhile((x) => x.isEven); + it = skipWhileEven.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileTrue = list2.skipWhile((x) => true); + it = skipWhileTrue.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileEven = list2.skipWhile((x) => x.isEven); + it = skipWhileEven.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileOdd = list2.skipWhile((x) => x.isOdd); + it = skipWhileOdd.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileFalse = list2.skipWhile((x) => false); + it = skipWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable skipWhileFalse2 = list3.skipWhile((x) => false); + Iterator it2 = skipWhileFalse2.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + Iterable skipWhileTrue2 = list3.skipWhile((x) => true); + it2 = skipWhileTrue2.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + skipWhileTrue = set1.skipWhile((x) => true); + it = skipWhileTrue.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileFalse = set1.skipWhile((x) => false); + List copied = skipWhileFalse.toList(); + Expect.equals(3, copied.length); + Expect.isTrue(set1.contains(copied[0])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(copied[0] != copied[1]); + Expect.isTrue(copied[0] != copied[2]); + Expect.isTrue(copied[1] != copied[2]); + it = skipWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it.current != null); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it.current != null); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it.current != null); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileTrue = set2.skipWhile((x) => true); + it = skipWhileTrue.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + skipWhileFalse = set2.skipWhile((x) => false); + it = skipWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); +} diff --git a/tests/corelib/iterable_take_test.dart b/tests/corelib/iterable_take_test.dart new file mode 100644 index 00000000000..3910769846f --- /dev/null +++ b/tests/corelib/iterable_take_test.dart @@ -0,0 +1,216 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Iterable take0 = list1.take(0); + Iterator it = take0.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable take1 = list1.take(1); + it = take1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable take2 = list1.take(2); + it = take2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable take3 = list1.take(3); + it = take3.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable take4 = list1.take(4); + it = take4.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take4 = list1.take(4); + take3 = take4.take(3); + take2 = take3.take(2); + take1 = take2.take(1); + take0 = take1.take(0); + it = take0.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = take1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = take2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = take3.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + it = take4.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take0 = list2.take(0); + it = take0.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take1 = list2.take(1); + it = take1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take2 = list2.take(2); + it = take2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take3 = list2.take(3); + it = take3.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable take02 = list3.take(0); + Iterator it2 = take02.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + Iterable take12 = list3.take(1); + it2 = take12.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + take0 = set1.take(0); + it = take0.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take1 = set1.take(1); + List copied = take1.toList(); + Expect.equals(1, copied.length); + Expect.isTrue(set1.contains(copied[0])); + it = take1.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take2 = set1.take(2); + copied = take2.toList(); + Expect.equals(2, copied.length); + Expect.isTrue(set1.contains(copied[0])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(copied[0] != copied[1]); + it = take2.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take3 = set1.take(3); + copied = take3.toList(); + Expect.equals(3, copied.length); + Expect.isTrue(set1.contains(copied[0])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(set1.contains(copied[2])); + Expect.isTrue(copied[0] != copied[1]); + Expect.isTrue(copied[0] != copied[2]); + Expect.isTrue(copied[1] != copied[2]); + it = take3.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isNotNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take0 = set2.take(0); + it = take0.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + take1 = set2.take(1); + it = take1.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); +} diff --git a/tests/corelib/iterable_take_while_test.dart b/tests/corelib/iterable_take_while_test.dart new file mode 100644 index 00000000000..6fbc08df997 --- /dev/null +++ b/tests/corelib/iterable_take_while_test.dart @@ -0,0 +1,130 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + + Iterable takeWhileFalse = list1.takeWhile((x) => false); + Iterator it = takeWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable takeWhileOdd = list1.takeWhile((x) => x.isOdd); + it = takeWhileOdd.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable takeWhileLessThan3 = list1.takeWhile((x) => x < 3); + it = takeWhileLessThan3.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable takeEverything = list1.takeWhile((x) => true); + it = takeEverything.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(3, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable takeWhileEven = list1.takeWhile((x) => x.isEven); + it = takeWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + takeWhileFalse = list2.takeWhile((x) => false); + it = takeWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + takeWhileEven = list2.takeWhile((x) => x.isEven); + it = takeWhileEven.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + takeEverything = list2.takeWhile((x) => true); + it = takeEverything.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(4, it.current); + Expect.isTrue(it.moveNext()); + Expect.equals(5, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + Iterable takeWhileFalse2 = list3.takeWhile((x) => false); + Iterator it2 = takeWhileFalse2.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + Iterable takeEverything2 = list3.takeWhile((x) => true); + it2 = takeEverything2.iterator; + Expect.isNull(it2.current); + Expect.isFalse(it2.moveNext()); + Expect.isNull(it2.current); + + takeWhileFalse = set1.takeWhile((x) => false); + it = takeWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + takeEverything = set1.takeWhile((x) => true); + List copied = takeEverything.toList(); + Expect.equals(3, copied.length); + Expect.isTrue(set1.contains(copied[0])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(set1.contains(copied[1])); + Expect.isTrue(copied[0] != copied[1]); + Expect.isTrue(copied[0] != copied[2]); + Expect.isTrue(copied[1] != copied[2]); + it = takeEverything.iterator; + Expect.isNull(it.current); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it.current != null); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it.current != null); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it.current != null); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + takeWhileFalse = set2.takeWhile((x) => false); + it = takeWhileFalse.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + + takeEverything = set2.takeWhile((x) => true); + it = takeEverything.iterator; + Expect.isNull(it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); +} diff --git a/tests/corelib/iterable_to_list_test.dart b/tests/corelib/iterable_to_list_test.dart new file mode 100644 index 00000000000..6cb3c5208d5 --- /dev/null +++ b/tests/corelib/iterable_to_list_test.dart @@ -0,0 +1,57 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 5]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + set2..add("foo") + ..add("bar") + ..add("toto"); + Set set3 = new Set(); + + var listCopy = list1.toList(); + Expect.listEquals(list1, listCopy); + Expect.isTrue(listCopy is List); + Expect.isFalse(listCopy is List); + Expect.isFalse(identical(list1, listCopy)); + + listCopy = list2.toList(); + Expect.listEquals(list2, listCopy); + Expect.isTrue(listCopy is List); + Expect.isFalse(listCopy is List); + Expect.isFalse(identical(list2, listCopy)); + + listCopy = list3.toList(); + Expect.listEquals(list3, listCopy); + Expect.isTrue(listCopy is List); + Expect.isFalse(listCopy is List); + Expect.isFalse(identical(list3, listCopy)); + + listCopy = set1.toList(); + Expect.equals(3, listCopy.length); + Expect.isTrue(listCopy.contains(11)); + Expect.isTrue(listCopy.contains(12)); + Expect.isTrue(listCopy.contains(13)); + Expect.isTrue(listCopy is List); + Expect.isFalse(listCopy is List); + + listCopy = set2.toList(); + Expect.equals(3, listCopy.length); + Expect.isTrue(listCopy.contains("foo")); + Expect.isTrue(listCopy.contains("bar")); + Expect.isTrue(listCopy.contains("toto")); + Expect.isTrue(listCopy is List); + Expect.isFalse(listCopy is List); + + listCopy = set3.toList(); + Expect.isTrue(listCopy.isEmpty); + Expect.isTrue(listCopy is List); + Expect.isTrue(listCopy is List); +} diff --git a/tests/corelib/iterable_to_set_test.dart b/tests/corelib/iterable_to_set_test.dart new file mode 100644 index 00000000000..a8188b831fc --- /dev/null +++ b/tests/corelib/iterable_to_set_test.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2012, 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. + +main() { + List list1 = [1, 2, 3]; + List list2 = const [4, 4]; + List list3 = []; + Set set1 = new Set(); + set1..add(11) + ..add(12) + ..add(13); + Set set2 = new Set(); + set2..add("foo") + ..add("bar") + ..add("toto"); + Set set3 = new Set(); + + var setCopy = list1.toSet(); + Expect.equals(3, setCopy.length); + Expect.isTrue(setCopy.contains(1)); + Expect.isTrue(setCopy.contains(2)); + Expect.isTrue(setCopy.contains(3)); + Expect.isTrue(setCopy is Set); + Expect.isFalse(setCopy is Set); + + setCopy = list2.toSet(); + Expect.equals(1, setCopy.length); + Expect.isTrue(setCopy.contains(4)); + Expect.isTrue(setCopy is Set); + Expect.isFalse(setCopy is Set); + + setCopy = list3.toSet(); + Expect.isTrue(setCopy.isEmpty); + Expect.isTrue(setCopy is Set); + Expect.isFalse(setCopy is Set); + + setCopy = set1.toSet(); + Expect.setEquals(set1, setCopy); + Expect.isTrue(setCopy is Set); + Expect.isFalse(setCopy is Set); + Expect.isFalse(identical(setCopy, set1)); + + setCopy = set2.toSet(); + Expect.setEquals(set2, setCopy); + Expect.isTrue(setCopy is Set); + Expect.isFalse(setCopy is Set); + Expect.isFalse(identical(setCopy, set2)); + + setCopy = set3.toSet(); + Expect.setEquals(set3, setCopy); + Expect.isTrue(setCopy is Set); + Expect.isTrue(setCopy is Set); + Expect.isFalse(identical(setCopy, set3)); +} diff --git a/tests/corelib/json_test.dart b/tests/corelib/json_test.dart new file mode 100644 index 00000000000..e0ece7bf869 --- /dev/null +++ b/tests/corelib/json_test.dart @@ -0,0 +1,249 @@ +// Copyright (c) 2012, 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. + +import "dart:json"; + +bool badFormat(e) => e is FormatException; + +void testJson(json, expected) { + var value = parse(json); + compare(expected, actual, path) { + if (expected is List) { + Expect.isTrue(actual is List); + Expect.equals(expected.length, actual.length, "$path: List length"); + for (int i = 0; i < expected.length; i++) { + compare(expected[i], actual[i], "$path[$i]"); + } + } else if (expected is Map) { + Expect.isTrue(actual is Map); + Expect.equals(expected.length, actual.length, "$path: Map size"); + expected.forEach((key, value) { + Expect.isTrue(actual.containsKey(key)); + compare(value, actual[key], "$path[$key]"); + }); + } else if (expected is num) { + Expect.equals(expected is int, actual is int, "$path: same number type"); + Expect.isTrue(expected.compareTo(actual) == 0, + "$path: $expected vs. $actual"); + } else { + // String, bool, null. + Expect.equals(expected, actual, path); + } + } + compare(expected, value, "value"); +} + +void testThrows(json) { + Expect.throws(() => parse(json), badFormat); +} + +testNumbers() { + // Positive tests for number formats. + var integerList = ["0","9","9999"]; + var signList = ["", "-"]; + var fractionList = ["", ".0", ".1", ".99999"]; + var exponentList = [""]; + for (var exphead in ["e", "E", "e-", "E-", "e+", "E+"]) { + for (var expval in ["0", "1", "200"]) { + exponentList.add("$exphead$expval"); + } + } + + for (var integer in integerList) { + for (var sign in signList) { + for (var fraction in fractionList) { + for (var exp in exponentList) { + var literal = "$sign$integer$fraction$exp"; + var parseNumber = + ((fraction == "" && exp == "") ? (String x) => int.parse(x) + : (String x) => double.parse(x)); + var expectedValue = parseNumber(literal); + testJson(literal, expectedValue); + } + } + } + } + + // Negative tests (syntax error). + // testError thoroughly tests the given parts with a lot of valid + // values for the other parts. + testError({signs, integers, fractions, exponents}) { + def(value, defaultValue) { + if (value == null) return defaultValue; + if (value is List) return value; + return [value]; + } + signs = def(signs, signList); + integers = def(integers, integerList); + fractions = def(fractions, fractionList); + exponents = def(exponents, exponentList); + for (var integer in integers) { + for (var sign in signs) { + for (var fraction in fractions) { + for (var exponent in exponents) { + var literal = "$sign$integer$fraction$exponent"; + testThrows(literal); + } + } + } + } + } + // Doubles overflow to Infinity. + testJson("1e+400", double.INFINITY); + // (Integers do not, but we don't have those on dart2js). + + // Integer part cannot be omitted: + testError(integers: ""); + // Initial zero only allowed for zero integer part. + testError(integers: ["00", "01"]); + // Only minus allowed as sign. + testError(signs: "+"); + // Requires digits after decimal point. + testError(fractions: "."); + // Requires exponent digts, and only digits. + testError(exponents: ["e", "e+", "e-", "e.0"]); + + // No whitespace inside numbers. + testThrows("- 2.2e+2"); + testThrows("-2 .2e+2"); + testThrows("-2. 2e+2"); + testThrows("-2.2 e+2"); + testThrows("-2.2e +2"); + testThrows("-2.2e+ 2"); + + testThrows("[2.,2]"); + testThrows("{2.:2}"); +} + +testStrings() { + // String parser accepts and understands escapes. + var input = r'"\u0000\uffff\n\r\f\t\b\/\\\"' '\x20\ufffd\uffff"'; + var expected = "\u0000\uffff\n\r\f\t\b\/\\\"\x20\ufffd\uffff"; + testJson(input, expected); + // Empty string. + testJson(r'""', ""); + // Escape first. + testJson(r'"\"........"', "\"........"); + // Escape last. + testJson(r'"........\""', "........\""); + // Escape middle. + testJson(r'"....\"...."', "....\"...."); + + // Does not accept single quotes. + testThrows(r"''"); + // Throws on unterminated strings. + testThrows(r'"......\"'); + // Throws on unterminated escapes. + testThrows(r'"\'); // ' is not escaped. + testThrows(r'"\a"'); + testThrows(r'"\u"'); + testThrows(r'"\u1"'); + testThrows(r'"\u12"'); + testThrows(r'"\u123"'); + testThrows(r'"\ux"'); + testThrows(r'"\u1x"'); + testThrows(r'"\u12x"'); + testThrows(r'"\u123x"'); + // Throws on bad escapes. + testThrows(r'"\a"'); + testThrows(r'"\x00"'); + testThrows(r'"\c2"'); + testThrows(r'"\000"'); + testThrows(r'"\u{0}"'); + testThrows(r'"\%"'); + testThrows('"\\\x00"'); // Not raw string! + // Throws on control characters. + for (int i = 0; i < 32; i++) { + var string = new String.fromCharCodes([0x22,i,0x22]); // '"\x00"' etc. + testThrows(string); + } +} + + +testObjects() { + testJson(r'{}', {}); + testJson(r'{"x":42}', {"x":42}); + testJson(r'{"x":{"x":{"x":42}}}', {"x": {"x": {"x": 42}}}); + testJson(r'{"x":10,"x":42}', {"x": 42}); + testJson(r'{"":42}', {"": 42}); + + // Keys must be strings. + testThrows(r'{x:10}'); + testThrows(r'{true:10}'); + testThrows(r'{false:10}'); + testThrows(r'{null:10}'); + testThrows(r'{42:10}'); + testThrows(r'{42e1:10}'); + testThrows(r'{-42:10}'); + testThrows(r'{["text"]:10}'); + testThrows(r'{:10}'); +} + +testArrays() { + testJson(r'[]', []); + testJson(r'[1.1e1,"string",true,false,null,{}]', + [1.1e1, "string", true, false, null, {}]); + testJson(r'[[[[[[]]]],[[[]]],[[]]]]', [[[[[[]]]],[[[]]],[[]]]]); + testJson(r'[{},[{}],{"x":[]}]', [{},[{}],{"x":[]}]); + + testThrows(r'[1,,2]'); + testThrows(r'[1,2,]'); + testThrows(r'[,2]'); +} + +testWords() { + testJson(r'true', true); + testJson(r'false', false); + testJson(r'null', null); + testJson(r'[true]', [true]); + testJson(r'{"true":true}', {"true": true}); + + testThrows(r'truefalse'); + testThrows(r'trues'); + testThrows(r'nulll'); + testThrows(r'full'); + testThrows(r'nul'); + testThrows(r'tru'); + testThrows(r'fals'); + testThrows(r'\null'); + testThrows(r't\rue'); + testThrows(r't\rue'); +} + +testWhitespace() { + // Valid white-space characters. + var v = '\t\r\n\ '; + // Invalid white-space and non-recognized characters. + var invalids = ['\x00', '\f', '\x08', '\\', '\xa0','\u2028', '\u2029']; + + // Valid whitespace accepted "everywhere". + testJson('$v[${v}-2.2e2$v,$v{$v"key"$v:${v}true$v}$v,$v"ab"$v]$v', + [-2.2e2, {"key": true}, "ab"]); + + for (var i in invalids) { + testThrows('${i}"s"'); + testThrows('"s"${i}'); + testThrows('42${i}'); + testThrows('$i[]'); + testThrows('[$i]'); + testThrows('[$i"s"]'); + testThrows('["s"$i]'); + testThrows('[]$i'); + testThrows('$i{"k":"v"}'); + testThrows('{$i"k":"v"}'); + testThrows('{"k"$i:"v"}'); + testThrows('{"k":$i"v"}'); + testThrows('{"k":"v"$i}'); + testThrows('{"k":"v"}$i'); + } +} + +main() { + testNumbers(); + testStrings(); + testWords(); + testObjects(); + testArrays(); + testWhitespace(); +} diff --git a/tests/corelib/linked_hash_map_test.dart b/tests/corelib/linked_hash_map_test.dart index f90fa888b0c..ba39eed29c7 100644 --- a/tests/corelib/linked_hash_map_test.dart +++ b/tests/corelib/linked_hash_map_test.dart @@ -13,8 +13,8 @@ class LinkedHashMapTest { map["d"] = 4; map["e"] = 5; - List keys = new List(5); - List values = new List(5); + List keys = new List.fixedLength(5); + List values = new List.fixedLength(5); int index; diff --git a/tests/corelib/list_first_test.dart b/tests/corelib/list_first_test.dart index cdd718be90e..c0795a45288 100644 --- a/tests/corelib/list_first_test.dart +++ b/tests/corelib/list_first_test.dart @@ -4,7 +4,7 @@ void test(List list) { if (list.isEmpty) { - Expect.throws(() => list.first, (e) => e is RangeError); + Expect.throws(() => list.first, (e) => e is StateError); } else { Expect.equals(list[0], list.first); } diff --git a/tests/corelib/list_fixed_test.dart b/tests/corelib/list_fixed_test.dart new file mode 100644 index 00000000000..b6d74402ec6 --- /dev/null +++ b/tests/corelib/list_fixed_test.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2012, 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. + +main() { + var a; + + a = new List.fixedLength(42); + Expect.equals(42, a.length); + Expect.throws(() => a.add(499), (e) => e is UnsupportedError); + Expect.equals(42, a.length); + for (int i = 0; i < 42; i++) { + Expect.equals(null, a[i]); + } + Expect.throws(() => a.clear(), (e) => e is UnsupportedError); + Expect.equals(42, a.length); + + a = new List.fixedLength(42, fill: -2); + Expect.equals(42, a.length); + Expect.throws(() => a.add(499), (e) => e is UnsupportedError); + Expect.equals(42, a.length); + for (int i = 0; i < 42; i++) { + Expect.equals(-2, a[i]); + } + Expect.throws(() => a.clear(), (e) => e is UnsupportedError); + Expect.equals(42, a.length); +} diff --git a/tests/corelib/list_growable_test.dart b/tests/corelib/list_growable_test.dart new file mode 100644 index 00000000000..5066c127fa3 --- /dev/null +++ b/tests/corelib/list_growable_test.dart @@ -0,0 +1,60 @@ +// Copyright (c) 2012, 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. + +main() { + var a; + a = new List(); + a.add(499); + Expect.equals(1, a.length); + Expect.equals(499, a[0]); + a.clear(); + Expect.equals(0, a.length); + Expect.throws(() => a[0], (e) => e is RangeError); + + a = new List(42); + Expect.equals(42, a.length); + a.add(499); + Expect.equals(43, a.length); + Expect.equals(499, a[42]); + Expect.equals(null, a[23]); + a.clear(); + Expect.equals(0, a.length); + Expect.throws(() => a[0], (e) => e is RangeError); + + a = new List(42); + Expect.equals(42, a.length); + a.add(499); + Expect.equals(43, a.length); + Expect.equals(499, a[42]); + for (int i = 0; i < 42; i++) { + Expect.equals(null, a[i]); + } + a.clear(); + Expect.equals(0, a.length); + Expect.throws(() => a[0], (e) => e is RangeError); + + a = new List.filled(42, -1); + Expect.equals(42, a.length); + a.add(499); + Expect.equals(43, a.length); + Expect.equals(499, a[42]); + for (int i = 0; i < 42; i++) { + Expect.equals(-1, a[i]); + } + a.clear(); + Expect.equals(0, a.length); + Expect.throws(() => a[0], (e) => e is RangeError); + + a = new List.filled(42, -1); + Expect.equals(42, a.length); + a.add(499); + Expect.equals(43, a.length); + Expect.equals(499, a[42]); + for (int i = 0; i < 42; i++) { + Expect.equals(-1, a[i]); + } + a.clear(); + Expect.equals(0, a.length); + Expect.throws(() => a[0], (e) => e is RangeError); +} diff --git a/tests/corelib/list_index_of_test.dart b/tests/corelib/list_index_of_test.dart index ca8ab4c32d7..c217f41add1 100644 --- a/tests/corelib/list_index_of_test.dart +++ b/tests/corelib/list_index_of_test.dart @@ -4,7 +4,7 @@ class ListIndexOfTest { static testMain() { - test(new List(5)); + test(new List.fixedLength(5)); var l = new List(); l.length = 5; test(l); diff --git a/tests/corelib/list_iterators_test.dart b/tests/corelib/list_iterators_test.dart index 6f29061fb0f..0be3cf8e061 100644 --- a/tests/corelib/list_iterators_test.dart +++ b/tests/corelib/list_iterators_test.dart @@ -4,39 +4,42 @@ class ListIteratorsTest { static void checkListIterator(List a) { - Iterator it = a.iterator(); - Expect.equals(false, it.hasNext == a.isEmpty); + Iterator it = a.iterator; for (int i = 0; i < a.length; i++) { - Expect.equals(true, it.hasNext); - var elem = it.next(); + Expect.isTrue(it.moveNext()); + var elem = it.current; + Expect.equals(a[i], elem); } - Expect.equals(false, it.hasNext); - bool exceptionCaught = false; - try { - var eleme = it.next(); - } on StateError catch (e) { - exceptionCaught = true; - } - Expect.equals(true, exceptionCaught); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static testMain() { checkListIterator([]); checkListIterator([1, 2]); - checkListIterator(new List(0)); - checkListIterator(new List(10)); + checkListIterator(new List.fixedLength(0)); + checkListIterator(new List.fixedLength(10)); checkListIterator(new List()); List g = new List(); - g.addAll([1, 2]); + g.addAll([1, 2, 3]); checkListIterator(g); - Iterator it = g.iterator(); - Expect.equals(true, it.hasNext); + // This is mostly undefined behavior. + Iterator it = g.iterator; + Expect.isTrue(it.moveNext()); g.removeLast(); - Expect.equals(true, it.hasNext); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + g[1] = 49; + // The iterator keeps the last value. + Expect.equals(2, it.current); g.removeLast(); - Expect.equals(false, it.hasNext); + // The iterator keeps the last value. + Expect.equals(2, it.current); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + g.clear(); g.addAll([10, 20]); int sum = 0; for (var elem in g) { diff --git a/tests/corelib/list_last_test.dart b/tests/corelib/list_last_test.dart new file mode 100644 index 00000000000..4d9b53a9ada --- /dev/null +++ b/tests/corelib/list_last_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2012, 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. + +void test(List list) { + if (list.isEmpty) { + Expect.throws(() => list.last, (e) => e is StateError); + } else { + Expect.equals(list[list.length - 1], list.last); + } +} + +main() { + test([1, 2, 3]); + test(const ["foo", "bar"]); + test([]); + test(const []); +} diff --git a/tests/corelib/list_removeat_test.dart b/tests/corelib/list_removeat_test.dart index d6a9b28bcef..df7ac16594a 100644 --- a/tests/corelib/list_removeat_test.dart +++ b/tests/corelib/list_removeat_test.dart @@ -42,7 +42,7 @@ void main() { Expect.equals(3, l1.length, "length-2"); // Fixed size list. - var l2 = new List(5); + var l2 = new List.fixedLength(5); for (var i = 0; i < 5; i++) l2[i] = i; Expect.throws(() { l2.removeAt(2); }, (e) => e is UnsupportedError, diff --git a/tests/corelib/list_set_range_test.dart b/tests/corelib/list_set_range_test.dart index f96ede55572..ff91fe7603b 100644 --- a/tests/corelib/list_set_range_test.dart +++ b/tests/corelib/list_set_range_test.dart @@ -82,7 +82,7 @@ void testNegativeIndices() { } void testNonExtendableList() { - var list = new List(6); + var list = new List.fixedLength(6); Expect.listEquals([null, null, null, null, null, null], list); list.setRange(0, 3, [1, 2, 3, 4]); list.setRange(3, 3, [1, 2, 3, 4]); diff --git a/tests/corelib/list_test.dart b/tests/corelib/list_test.dart index 672504f123e..970eba5e16c 100644 --- a/tests/corelib/list_test.dart +++ b/tests/corelib/list_test.dart @@ -21,14 +21,14 @@ class ListTest { static void testClosures(List list) { testMap(val) {return val * 2 + 10; } - Collection mapped = list.map(testMap); + List mapped = list.mappedBy(testMap).toList(); Expect.equals(mapped.length, list.length); for (var i = 0; i < list.length; i++) { Expect.equals(mapped[i], list[i]*2 + 10); } testFilter(val) { return val == 3; } - Collection filtered = list.filter(testFilter); + Iterable filtered = list.where(testFilter); Expect.equals(filtered.length, 1); testEvery(val) { return val != 11; } @@ -36,20 +36,20 @@ class ListTest { Expect.equals(true, test); testSome(val) { return val == 1; } - test = list.some(testSome); + test = list.any(testSome); Expect.equals(true, test); testSomeFirst(val) { return val == 0; } - test = list.some(testSomeFirst); + test = list.any(testSomeFirst); Expect.equals(true, test); testSomeLast(val) { return val == (list.length - 1); } - test = list.some(testSomeLast); + test = list.any(testSomeLast); Expect.equals(true, test); } static void testList() { - List list = new List(4); + List list = new List.fixedLength(4); Expect.equals(list.length, 4); list[0] = 4; expectValues(list, 4, null, null, null); diff --git a/tests/corelib/map_keys2_test.dart b/tests/corelib/map_keys2_test.dart new file mode 100644 index 00000000000..5cb051f47e7 --- /dev/null +++ b/tests/corelib/map_keys2_test.dart @@ -0,0 +1,32 @@ +// 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. + +main() { + var map1 = { "foo": 42, "bar": 499 }; + var map2 = {}; + var map3 = const { "foo": 42, "bar": 499 }; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.keys is Iterable); + Expect.isFalse(map1.keys is Iterable); + + Expect.isTrue(map2.keys is Iterable); + Expect.isFalse(map2.keys is Iterable); + + Expect.isTrue(map3.keys is Iterable); + Expect.isFalse(map3.keys is Iterable); + + Expect.isTrue(map4.keys is Iterable); + Expect.isFalse(map4.keys is Iterable); + + Expect.isTrue(map5.keys is Iterable); + Expect.isFalse(map5.keys is Iterable); + + Expect.isTrue(map6.keys is Iterable); + Expect.isFalse(map6.keys is Iterable); +} diff --git a/tests/corelib/map_keys_test.dart b/tests/corelib/map_keys_test.dart new file mode 100644 index 00000000000..9297f03e060 --- /dev/null +++ b/tests/corelib/map_keys_test.dart @@ -0,0 +1,45 @@ +// 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. + +main() { + var map1 = { "foo": 42, "bar": 499 }; + var map2 = {}; + var map3 = const { "foo": 42, "bar": 499 }; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.keys is Iterable); + Expect.isFalse(map1.keys is List); + Expect.equals(2, map1.keys.length); + Expect.equals("foo", map1.keys.first); + Expect.equals("bar", map1.keys.last); + + Expect.isTrue(map2.keys is Iterable); + Expect.isFalse(map2.keys is List); + Expect.equals(0, map2.keys.length); + + Expect.isTrue(map3.keys is Iterable); + Expect.isFalse(map3.keys is List); + Expect.equals(2, map3.keys.length); + Expect.equals("foo", map3.keys.first); + Expect.equals("bar", map3.keys.last); + + Expect.isTrue(map4.keys is Iterable); + Expect.isFalse(map4.keys is List); + Expect.equals(0, map4.keys.length); + + Expect.isTrue(map5.keys is Iterable); + Expect.isFalse(map5.keys is List); + Expect.equals(2, map5.keys.length); + Expect.isTrue(map5.keys.first == "foo" || map5.keys.first == "bar"); + Expect.isTrue(map5.keys.last == "foo" || map5.keys.first == "bar"); + Expect.notEquals(map5.keys.first, map5.keys.last); + + Expect.isTrue(map6.keys is Iterable); + Expect.isFalse(map6.keys is List); + Expect.equals(0, map6.keys.length); +} diff --git a/tests/corelib/map_test.dart b/tests/corelib/map_test.dart index c7735e37685..40cfab554bd 100644 --- a/tests/corelib/map_test.dart +++ b/tests/corelib/map_test.dart @@ -152,7 +152,7 @@ class MapTest { void testForEachCollection(value) { other_map[value] = value; } - Collection keys = map.keys; + Iterable keys = map.keys; keys.forEach(testForEachCollection); Expect.equals(true, other_map.containsKey(key1)); Expect.equals(true, other_map.containsKey(key2)); @@ -167,7 +167,7 @@ class MapTest { Expect.equals(0, other_map.length); // Test Collection.values. - Collection values = map.values; + Iterable values = map.values; values.forEach(testForEachCollection); Expect.equals(true, !other_map.containsKey(key1)); Expect.equals(true, !other_map.containsKey(key2)); @@ -211,7 +211,7 @@ class MapTest { }); Expect.equals(6, sum); - List values = m.keys; + List values = m.keys.toList(); Expect.equals(3, values.length); String first = values[0]; String second = values[1]; diff --git a/tests/corelib/map_values2_test.dart b/tests/corelib/map_values2_test.dart new file mode 100644 index 00000000000..08b426a595e --- /dev/null +++ b/tests/corelib/map_values2_test.dart @@ -0,0 +1,51 @@ +// 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. + +main() { + var map1 = { "foo": 42, "bar": 499 }; + var map2 = {}; + var map3 = const { "foo": 42, "bar": 499 }; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.values is Iterable); + Expect.isFalse(map1.values is Iterable); + Expect.isFalse(map1.values is List); + Expect.equals(2, map1.values.length); + Expect.equals(42, map1.values.first); + Expect.equals(499, map1.values.last); + + Expect.isTrue(map2.values is Iterable); + Expect.isFalse(map2.values is Iterable); + Expect.isFalse(map2.values is List); + Expect.equals(0, map2.values.length); + + Expect.isTrue(map3.values is Iterable); + Expect.isFalse(map3.values is Iterable); + Expect.isFalse(map3.values is List); + Expect.equals(2, map3.values.length); + Expect.equals(42, map3.values.first); + Expect.equals(499, map3.values.last); + + Expect.isTrue(map4.values is Iterable); + Expect.isFalse(map4.values is Iterable); + Expect.isFalse(map4.values is List); + Expect.equals(0, map4.values.length); + + Expect.isTrue(map5.values is Iterable); + Expect.isFalse(map5.values is Iterable); + Expect.isFalse(map5.values is List); + Expect.equals(2, map5.values.length); + Expect.isTrue(map5.values.first == 43 || map5.values.first == 500); + Expect.isTrue(map5.values.last == 43 || map5.values.first == 500); + Expect.notEquals(map5.values.first, map5.values.last); + + Expect.isTrue(map6.values is Iterable); + Expect.isFalse(map6.values is Iterable); + Expect.isFalse(map6.values is List); + Expect.equals(0, map6.values.length); +} diff --git a/tests/corelib/map_values_test.dart b/tests/corelib/map_values_test.dart new file mode 100644 index 00000000000..699a2cc90f3 --- /dev/null +++ b/tests/corelib/map_values_test.dart @@ -0,0 +1,45 @@ +// 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. + +main() { + var map1 = { "foo": 42, "bar": 499 }; + var map2 = {}; + var map3 = const { "foo": 42, "bar": 499 }; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.values is Iterable); + Expect.isFalse(map1.values is List); + Expect.equals(2, map1.values.length); + Expect.equals(42, map1.values.first); + Expect.equals(499, map1.values.last); + + Expect.isTrue(map2.values is Iterable); + Expect.isFalse(map2.values is List); + Expect.equals(0, map2.values.length); + + Expect.isTrue(map3.values is Iterable); + Expect.isFalse(map3.values is List); + Expect.equals(2, map3.values.length); + Expect.equals(42, map3.values.first); + Expect.equals(499, map3.values.last); + + Expect.isTrue(map4.values is Iterable); + Expect.isFalse(map4.values is List); + Expect.equals(0, map4.values.length); + + Expect.isTrue(map5.values is Iterable); + Expect.isFalse(map5.values is List); + Expect.equals(2, map5.values.length); + Expect.isTrue(map5.values.first == 43 || map5.values.first == 500); + Expect.isTrue(map5.values.last == 43 || map5.values.first == 500); + Expect.notEquals(map5.values.first, map5.values.last); + + Expect.isTrue(map6.values is Iterable); + Expect.isFalse(map6.values is List); + Expect.equals(0, map6.values.length); +} diff --git a/tests/corelib/num_clamp_test.dart b/tests/corelib/num_clamp_test.dart new file mode 100644 index 00000000000..662cab8a173 --- /dev/null +++ b/tests/corelib/num_clamp_test.dart @@ -0,0 +1,78 @@ +// Copyright (c) 2012, 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. +// Test num.clamp. + +testIntClamp() { + Expect.equals(2, 2.clamp(1, 3)); + Expect.equals(1, 0.clamp(1, 3)); + Expect.equals(3, 4.clamp(1, 3)); + Expect.equals(-2, (-2).clamp(-3, -1)); + Expect.equals(-1, 0.clamp(-3, -1)); + Expect.equals(-3, (-4).clamp(-3, -1)); + Expect.equals(0, 1.clamp(0, 0)); + Expect.equals(0, (-1).clamp(0, 0)); + Expect.equals(0, 0.clamp(0, 0)); + Expect.throws(() => 0.clamp(0, -1), (e) => e is ArgumentError); + Expect.throws(() => 0.clamp("str", -1), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.clamp(0, "2"), + (e) => e is ArgumentError || e is TypeError); +} + +testDoubleClamp() { + Expect.equals(2.0, 2.clamp(1.0, 3.0)); + Expect.equals(1.0, 0.clamp(1.0, 3.0)); + Expect.equals(3.0, 4.clamp(1.0, 3.0)); + Expect.equals(-2.0, (-2.0).clamp(-3.0, -1.0)); + Expect.equals(-1.0, 0.0.clamp(-3.0, -1.0)); + Expect.equals(-3.0, (-4.0).clamp(-3.0, -1.0)); + Expect.equals(0.0, 1.0.clamp(0.0, 0.0)); + Expect.equals(0.0, (-1.0).clamp(0.0, 0.0)); + Expect.equals(0.0, 0.0.clamp(0.0, 0.0)); + Expect.throws(() => 0.0.clamp(0.0, -1.0), (e) => e is ArgumentError); + Expect.throws(() => 0.0.clamp("str", -1.0), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.0.clamp(0.0, "2"), + (e) => e is ArgumentError || e is TypeError); +} + +testDoubleClampInt() { + Expect.equals(2.0, 2.0.clamp(1, 3)); + Expect.equals(1, 0.0.clamp(1, 3)); + Expect.isTrue(0.0.clamp(1, 3) is int); + Expect.equals(3, 4.0.clamp(1, 3)); + Expect.isTrue(4.0.clamp(1, 3) is int); + Expect.equals(-2.0, (-2.0).clamp(-3, -1)); + Expect.equals(-1, 0.0.clamp(-3, -1)); + Expect.isTrue(0.0.clamp(-3, -1) is int); + Expect.equals(-3, (-4.0).clamp(-3, -1)); + Expect.isTrue((-4.0).clamp(-3, -1) is int); + Expect.equals(0, 1.0.clamp(0, 0)); + Expect.isTrue(1.0.clamp(0, 0) is int); + Expect.equals(0, (-1.0).clamp(0, 0)); + Expect.isTrue((-1.0).clamp(0, 0) is int); + Expect.equals(0.0, 0.0.clamp(0, 0)); + Expect.isTrue(0.0.clamp(0, 0) is double); + Expect.throws(() => 0.0.clamp(0, -1), (e) => e is ArgumentError); + Expect.throws(() => 0.0.clamp("str", -1), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.0.clamp(0, "2"), + (e) => e is ArgumentError || e is TypeError); +} + +testDoubleClampExtremes() { + Expect.equals(2.0, 2.0.clamp(-double.INFINITY, double.INFINITY)); + Expect.equals(2.0, 2.0.clamp(-double.INFINITY, double.NAN)); + Expect.equals(double.INFINITY, 2.0.clamp(double.INFINITY, double.NAN)); + Expect.isTrue(2.0.clamp(double.NAN, double.NAN).isNaN); + Expect.throws(() => 0.0.clamp(double.NAN, double.INFINITY), + (e) => e is ArgumentError); +} + +main() { + testIntClamp(); + testDoubleClamp(); + testDoubleClampInt(); + testDoubleClampExtremes(); +} diff --git a/tests/corelib/queue_first_test.dart b/tests/corelib/queue_first_test.dart new file mode 100644 index 00000000000..209d5918de2 --- /dev/null +++ b/tests/corelib/queue_first_test.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2012, 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. + +main() { + Queue queue1 = new Queue(); + queue1..add(11) + ..add(12) + ..add(13); + Queue queue2 = new Queue(); + + Expect.equals(11, queue1.first); + Expect.throws(() => queue2.first, (e) => e is StateError); +} diff --git a/tests/corelib/queue_iterator_test.dart b/tests/corelib/queue_iterator_test.dart index 4f9ffff019b..ca1d9ab7c67 100644 --- a/tests/corelib/queue_iterator_test.dart +++ b/tests/corelib/queue_iterator_test.dart @@ -9,21 +9,10 @@ class QueueIteratorTest { testEmptyQueue(); } - static void testThrows(Iterator it) { - Expect.equals(false, it.hasNext); - var exception = null; - try { - it.next(); - } on StateError catch (e) { - exception = e; - } - Expect.equals(true, exception != null); - } - static int sum(int expected, Iterator it) { int count = 0; - while (it.hasNext) { - count += it.next(); + while (it.moveNext()) { + count += it.current; } Expect.equals(expected, count); } @@ -34,10 +23,10 @@ class QueueIteratorTest { queue.addLast(2); queue.addLast(3); - Iterator it = queue.iterator(); - Expect.equals(true, it.hasNext); + Iterator it = queue.iterator; sum(6, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static void testLargeQueue() { @@ -47,18 +36,18 @@ class QueueIteratorTest { count += i; queue.addLast(i); } - Iterator it = queue.iterator(); - Expect.equals(true, it.hasNext); + Iterator it = queue.iterator; sum(count, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static void testEmptyQueue() { Queue queue = new Queue(); - Iterator it = queue.iterator(); - Expect.equals(false, it.hasNext); + Iterator it = queue.iterator; sum(0, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } } diff --git a/tests/corelib/queue_last_test.dart b/tests/corelib/queue_last_test.dart new file mode 100644 index 00000000000..39983ba28dd --- /dev/null +++ b/tests/corelib/queue_last_test.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2012, 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. + +main() { + Queue queue1 = new Queue(); + queue1..add(11) + ..add(12) + ..add(13); + Queue queue2 = new Queue(); + + Expect.equals(13, queue1.last); + Expect.throws(() => queue2.last, (e) => e is StateError); +} diff --git a/tests/corelib/queue_single_test.dart b/tests/corelib/queue_single_test.dart new file mode 100644 index 00000000000..077c507f1cd --- /dev/null +++ b/tests/corelib/queue_single_test.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2012, 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. + +main() { + Queue queue1 = new Queue(); + queue1.add(42); + Queue queue2 = new Queue(); + queue2..add(11) + ..add(12) + ..add(13); + Queue queue3 = new Queue(); + + Expect.equals(42, queue1.single); + Expect.throws(() => queue2.single, (e) => e is StateError); + Expect.throws(() => queue3.single, (e) => e is StateError); +} diff --git a/tests/corelib/queue_test.dart b/tests/corelib/queue_test.dart index 0095f35890d..953721bd25f 100644 --- a/tests/corelib/queue_test.dart +++ b/tests/corelib/queue_test.dart @@ -41,17 +41,17 @@ class QueueTest { return (value == 10); } - Queue mapped = queue.map(mapTest); + Queue mapped = new Queue.from(queue.mappedBy(mapTest)); checkQueue(mapped, 3, 111); checkQueue(queue, 3, 1110); Expect.equals(1, mapped.removeFirst()); Expect.equals(100, mapped.removeLast()); Expect.equals(10, mapped.removeFirst()); - Queue other = queue.filter(is10); + Queue other = new Queue.from(queue.where(is10)); checkQueue(other, 1, 10); - Expect.equals(true, queue.some(is10)); + Expect.equals(true, queue.any(is10)); bool isInstanceOfInt(int value) { return (value is int); @@ -64,7 +64,7 @@ class QueueTest { bool is1(int value) { return (value == 1); } - Expect.equals(false, queue.some(is1)); + Expect.equals(false, queue.any(is1)); queue.clear(); Expect.equals(0, queue.length); @@ -98,7 +98,7 @@ class QueueTest { return (value > 1); } - other = queue.filter(isGreaterThanOne); + other = new Queue.from(queue.where(isGreaterThanOne)); checkQueue(other, 2, 5); testAddAll(); diff --git a/tests/corelib/range_error_test.dart b/tests/corelib/range_error_test.dart index e83bd30dfb9..62be0b862e2 100644 --- a/tests/corelib/range_error_test.dart +++ b/tests/corelib/range_error_test.dart @@ -14,7 +14,7 @@ class RangeErrorTest { testListRead(list, -1); testListRead(list, 1); - list = new List(1); + list = new List.fixedLength(1); testListRead(list, -1); testListRead(list, 1); @@ -33,7 +33,7 @@ class RangeErrorTest { testListWrite(list, -1); testListWrite(list, 1); - list = new List(1); + list = new List.fixedLength(1); testListWrite(list, -1); testListWrite(list, 1); diff --git a/tests/corelib/reg_exp1_test.dart b/tests/corelib/reg_exp1_test.dart index 7d3557ecace..50cd4afeedf 100644 --- a/tests/corelib/reg_exp1_test.dart +++ b/tests/corelib/reg_exp1_test.dart @@ -11,16 +11,16 @@ class RegExp1Test { Expect.equals(false, exp1.hasMatch("gim")); Expect.equals(true, exp1.hasMatch("just foo")); Expect.equals("bar|foo", exp1.pattern); - Expect.equals(false, exp1.multiLine); - Expect.equals(false, exp1.ignoreCase); + Expect.equals(false, exp1.isMultiLine); + Expect.equals(true, exp1.isCaseSensitive); - RegExp exp2 = new RegExp("o+", ignoreCase: true); + RegExp exp2 = new RegExp("o+", caseSensitive: false); Expect.equals(true, exp2.hasMatch("this looks good")); Expect.equals(true, exp2.hasMatch("fOO")); Expect.equals(false, exp2.hasMatch("bar")); Expect.equals("o+", exp2.pattern); - Expect.equals(true, exp2.ignoreCase); - Expect.equals(false, exp2.multiLine); + Expect.equals(false, exp2.isCaseSensitive); + Expect.equals(false, exp2.isMultiLine); } } diff --git a/tests/corelib/reg_exp5_test.dart b/tests/corelib/reg_exp5_test.dart index 56002cac03e..3a1aa7f9e01 100644 --- a/tests/corelib/reg_exp5_test.dart +++ b/tests/corelib/reg_exp5_test.dart @@ -17,7 +17,7 @@ main() { Expect.equals(null, fm); Iterable am = new RegExp(r"^\w+$").allMatches(str); - Expect.isFalse(am.iterator().hasNext); + Expect.isFalse(am.iterator.moveNext()); Expect.equals(null, new RegExp(r"^\w+$").stringMatch(str)); } diff --git a/tests/corelib/reg_exp_all_matches_test.dart b/tests/corelib/reg_exp_all_matches_test.dart index fb4616c2f06..27c8ea7e990 100644 --- a/tests/corelib/reg_exp_all_matches_test.dart +++ b/tests/corelib/reg_exp_all_matches_test.dart @@ -7,26 +7,26 @@ class RegExpAllMatchesTest { static testIterator() { var matches = new RegExp("foo").allMatches("foo foo"); - Iterator it = matches.iterator(); - Expect.equals(true, it.hasNext); - Expect.equals('foo', it.next().group(0)); - Expect.equals(true, it.hasNext); - Expect.equals('foo', it.next().group(0)); - Expect.equals(false, it.hasNext); + Iterator it = matches.iterator; + Expect.isTrue(it.moveNext()); + Expect.equals('foo', it.current.group(0)); + Expect.isTrue(it.moveNext()); + Expect.equals('foo', it.current.group(0)); + Expect.isFalse(it.moveNext()); // Run two iterators over the same results. - it = matches.iterator(); - Iterator it2 = matches.iterator(); - Expect.equals(true, it.hasNext); - Expect.equals(true, it2.hasNext); - Expect.equals('foo', it.next().group(0)); - Expect.equals('foo', it2.next().group(0)); - Expect.equals(true, it.hasNext); - Expect.equals(true, it2.hasNext); - Expect.equals('foo', it.next().group(0)); - Expect.equals('foo', it2.next().group(0)); - Expect.equals(false, it.hasNext); - Expect.equals(false, it2.hasNext); + it = matches.iterator; + Iterator it2 = matches.iterator; + Expect.isTrue(it.moveNext()); + Expect.isTrue(it2.moveNext()); + Expect.equals('foo', it.current.group(0)); + Expect.equals('foo', it2.current.group(0)); + Expect.isTrue(it.moveNext()); + Expect.isTrue(it2.moveNext()); + Expect.equals('foo', it.current.group(0)); + Expect.equals('foo', it2.current.group(0)); + Expect.equals(false, it.moveNext()); + Expect.equals(false, it2.moveNext()); } static testForEach() { @@ -40,7 +40,7 @@ class RegExpAllMatchesTest { static testMap() { var matches = new RegExp("foo?").allMatches("foo fo foo fo"); - var mapped = matches.map((Match m) => "${m.group(0)}bar"); + var mapped = matches.mappedBy((Match m) => "${m.group(0)}bar"); Expect.equals(4, mapped.length); var strbuf = new StringBuffer(); for (String s in mapped) { @@ -51,7 +51,7 @@ class RegExpAllMatchesTest { static testFilter() { var matches = new RegExp("foo?").allMatches("foo fo foo fo"); - var filtered = matches.filter((Match m) { + var filtered = matches.where((Match m) { return m.group(0) == 'foo'; }); Expect.equals(2, filtered.length); @@ -74,13 +74,13 @@ class RegExpAllMatchesTest { static testSome() { var matches = new RegExp("foo?").allMatches("foo fo foo fo"); - Expect.equals(true, matches.some((Match m) { + Expect.equals(true, matches.any((Match m) { return m.group(0).startsWith("fo"); })); - Expect.equals(true, matches.some((Match m) { + Expect.equals(true, matches.any((Match m) { return m.group(0).startsWith("foo"); })); - Expect.equals(false, matches.some((Match m) { + Expect.equals(false, matches.any((Match m) { return m.group(0).startsWith("fooo"); })); } diff --git a/tests/corelib/reg_exp_start_end_test.dart b/tests/corelib/reg_exp_start_end_test.dart index 80b4634a44d..18a7337e915 100644 --- a/tests/corelib/reg_exp_start_end_test.dart +++ b/tests/corelib/reg_exp_start_end_test.dart @@ -5,11 +5,11 @@ main() { var matches = new RegExp("(a(b)((c|de)+))").allMatches("abcde abcde abcde"); - var it = matches.iterator(); + var it = matches.iterator; int start = 0; int end = 5; - while (it.hasNext) { - Match match = it.next(); + while (it.moveNext()) { + Match match = it.current; Expect.equals(start, match.start); Expect.equals(end, match.end); start += 6; diff --git a/tests/corelib/set_iterator_test.dart b/tests/corelib/set_iterator_test.dart index 08135e4110f..d6ec16e2952 100644 --- a/tests/corelib/set_iterator_test.dart +++ b/tests/corelib/set_iterator_test.dart @@ -19,21 +19,10 @@ class SetIteratorTest { testDifferentHashCodes(); } - static void testThrows(Iterator it) { - Expect.equals(false, it.hasNext); - var exception = null; - try { - it.next(); - } on StateError catch (e) { - exception = e; - } - Expect.equals(true, exception != null); - } - static int sum(int expected, Iterator it) { int count = 0; - while (it.hasNext) { - count += it.next(); + while (it.moveNext()) { + count += it.current; } Expect.equals(expected, count); } @@ -44,10 +33,10 @@ class SetIteratorTest { set.add(2); set.add(3); - Iterator it = set.iterator(); - Expect.equals(true, it.hasNext); + Iterator it = set.iterator; sum(6, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static void testLargeSet() { @@ -57,18 +46,18 @@ class SetIteratorTest { count += i; set.add(i); } - Iterator it = set.iterator(); - Expect.equals(true, it.hasNext); + Iterator it = set.iterator; sum(count, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static void testEmptySet() { Set set = new Set(); - Iterator it = set.iterator(); - Expect.equals(false, it.hasNext); + Iterator it = set.iterator; sum(0, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static void testSetWithDeletedEntries() { @@ -79,10 +68,12 @@ class SetIteratorTest { for (int i = 0; i < 100; i++) { set.remove(i); } - Iterator it = set.iterator(); - Expect.equals(false, it.hasNext); + Iterator it = set.iterator; + Expect.isFalse(it.moveNext()); + it = set.iterator; sum(0, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); int count = 0; for (int i = 0; i < 100; i++) { @@ -90,10 +81,10 @@ class SetIteratorTest { if (i % 2 == 0) set.remove(i); else count += i; } - it = set.iterator(); - Expect.equals(true, it.hasNext); + it = set.iterator; sum(count, it); - testThrows(it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); } static void testBug5116829() { diff --git a/tests/corelib/set_test.dart b/tests/corelib/set_test.dart index 79821b59ffb..2a9cd1bf8a3 100644 --- a/tests/corelib/set_test.dart +++ b/tests/corelib/set_test.dart @@ -51,7 +51,7 @@ class SetTest { return val * val; } - Set mapped = set.map(testMap); + Set mapped = set.mappedBy(testMap).toSet(); Expect.equals(10, mapped.length); Expect.equals(true, mapped.contains(0)); @@ -79,7 +79,7 @@ class SetTest { return val.isEven; } - Set filtered = set.filter(testFilter); + Set filtered = set.where(testFilter).toSet(); Expect.equals(5, filtered.length); @@ -112,10 +112,10 @@ class SetTest { return (val == 4); } - Expect.equals(true, set.some(testSome)); - Expect.equals(true, filtered.some(testSome)); + Expect.equals(true, set.any(testSome)); + Expect.equals(true, filtered.any(testSome)); filtered.remove(4); - Expect.equals(false, filtered.some(testSome)); + Expect.equals(false, filtered.any(testSome)); // Test Set.intersection. Set intersection = set.intersection(filtered); @@ -138,7 +138,7 @@ class SetTest { Expect.equals(true, intersection.isSubsetOf(filtered)); // Test Set.addAll. - List list = new List(10); + List list = new List.fixedLength(10); for (int i = 0; i < 10; i++) { list[i] = i + 10; } diff --git a/tests/corelib/sort_helper.dart b/tests/corelib/sort_helper.dart index e37809746b6..85d0bee5641 100644 --- a/tests/corelib/sort_helper.dart +++ b/tests/corelib/sort_helper.dart @@ -23,7 +23,7 @@ class SortHelper { } void testSortIntLists() { - List a = new List(40); + List a = new List.fixedLength(40); for (int i = 0; i < a.length; i++) { a[i] = i; @@ -79,10 +79,10 @@ class SortHelper { a[33] = 1; testSort(a); - var a2 = new List(0); + var a2 = new List.fixedLength(0); testSort(a2); - var a3 = new List(1); + var a3 = new List.fixedLength(1); a3[0] = 1; testSort(a3); @@ -120,7 +120,7 @@ class SortHelper { } void testInsertionSort(int i1, int i2, int i3, int i4) { - var a = new List(4); + var a = new List.fixedLength(4); a[0] = i1; a[1] = i2; a[2] = i3; @@ -129,7 +129,7 @@ class SortHelper { } void testSortDoubleLists() { - List a = new List(40); + List a = new List.fixedLength(40); for (int i = 0; i < a.length; i++) { a[i] = 1.0 * i + 0.5; } diff --git a/tests/corelib/stopwatch_test.dart b/tests/corelib/stopwatch_test.dart index fe37b42de8c..b688ab3f377 100644 --- a/tests/corelib/stopwatch_test.dart +++ b/tests/corelib/stopwatch_test.dart @@ -5,13 +5,12 @@ // Dart test program for testing stopwatch support. library stopwatch_test; -import 'dart:math'; class StopwatchTest { static bool checkTicking(Stopwatch sw) { sw.start(); for (int i = 0; i < 10000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); if (sw.elapsedTicks > 0) { break; } @@ -27,7 +26,7 @@ class StopwatchTest { sw2.start(); int sw2LastElapsed = 0; for (int i = 0; i < 100000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); int v2 = sw.elapsedTicks; if (v1 != v2) { return false; @@ -49,7 +48,7 @@ class StopwatchTest { Stopwatch sw = new Stopwatch(); sw.start(); for (int i = 0; i < 100000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); if (sw.elapsedTicks > 0) { break; } @@ -58,7 +57,7 @@ class StopwatchTest { int initial = sw.elapsedTicks; sw.start(); for (int i = 0; i < 100000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); if (sw.elapsedTicks > initial) { break; } @@ -71,7 +70,7 @@ class StopwatchTest { Stopwatch sw = new Stopwatch(); sw.start(); for (int i = 0; i < 100000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); if (sw.elapsedTicks > 0) { break; } @@ -81,14 +80,14 @@ class StopwatchTest { Expect.equals(0, sw.elapsedTicks); sw.start(); for (int i = 0; i < 100000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); if (sw.elapsedTicks > 0) { break; } } sw.reset(); for (int i = 0; i < 100000; i++) { - parseInt(i.toString()); + int.parse(i.toString()); if (sw.elapsedTicks > 0) { break; } diff --git a/tests/corelib/string_base_vm_test.dart b/tests/corelib/string_base_vm_test.dart index 80ea797051b..f043f336d96 100644 --- a/tests/corelib/string_base_vm_test.dart +++ b/tests/corelib/string_base_vm_test.dart @@ -26,7 +26,7 @@ class StringBaseTest { static testCreation() { String s = "Hello"; - List a = new List(s.length); + List a = new List.fixedLength(s.length); List ga = new List(); bool exception_caught = false; for (int i = 0; i < a.length; i++) { diff --git a/tests/corelib/string_character_test.dart b/tests/corelib/string_character_test.dart new file mode 100644 index 00000000000..95d272cf1bb --- /dev/null +++ b/tests/corelib/string_character_test.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2012, 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. + +main() { + Expect.equals("A", new String.character(65)); + Expect.equals("B", new String.character(66)); + var gClef = new String.character(0x1D11E); + Expect.equals(2, gClef.length); + Expect.equals(0xD834, gClef.charCodeAt(0)); + Expect.equals(0xDD1E, gClef.charCodeAt(1)); + + // Unmatched surrogates. + var unmatched = new String.character(0xD800); + Expect.equals(1, unmatched.length); + Expect.equals(0xD800, unmatched.charCodeAt(0)); + unmatched = new String.character(0xDC00); + Expect.equals(1, unmatched.length); + Expect.equals(0xDC00, unmatched.charCodeAt(0)); + + Expect.throws(() => new String.character(-1), + (e) => e is ArgumentError); + + // Invalid code point. + Expect.throws(() => new String.character(0x110000), + (e) => e is ArgumentError); + + Expect.throws(() => new String.character(0x110001), + (e) => e is ArgumentError); +} diff --git a/tests/corelib/string_from_list_test.dart b/tests/corelib/string_from_list_test.dart index 23c90f251d9..99642a1c8c9 100644 --- a/tests/corelib/string_from_list_test.dart +++ b/tests/corelib/string_from_list_test.dart @@ -4,7 +4,7 @@ class StringFromListTest { static testMain() { - Expect.equals("", new String.fromCharCodes(new List(0))); + Expect.equals("", new String.fromCharCodes(new List.fixedLength(0))); Expect.equals("", new String.fromCharCodes([])); Expect.equals("", new String.fromCharCodes(const [])); Expect.equals("AB", new String.fromCharCodes([65, 66])); diff --git a/tests/corelib/string_pattern_test.dart b/tests/corelib/string_pattern_test.dart index 440855d1b78..6ab5e958dc9 100644 --- a/tests/corelib/string_pattern_test.dart +++ b/tests/corelib/string_pattern_test.dart @@ -18,15 +18,16 @@ testNoMatch() { // Also tests that RegExp groups don't work. String helloPattern = "with (hello)"; Iterable matches = helloPattern.allMatches(str); - Expect.isFalse(matches.iterator().hasNext); + Expect.isFalse(matches.iterator.moveNext()); } testOneMatch() { String helloPattern = "with hello"; Iterable matches = helloPattern.allMatches(str); - var iterator = matches.iterator(); - Match match = iterator.next(); - Expect.isFalse(iterator.hasNext); + var iterator = matches.iterator; + Expect.isTrue(iterator.moveNext()); + Match match = iterator.current; + Expect.isFalse(iterator.moveNext()); Expect.equals(str.indexOf('with', 0), match.start); Expect.equals(str.indexOf('with', 0) + helloPattern.length, match.end); Expect.equals(helloPattern, match.pattern); @@ -58,19 +59,19 @@ testTwoMatches() { testEmptyPattern() { String pattern = ""; Iterable matches = pattern.allMatches(str); - Expect.isTrue(matches.iterator().hasNext); + Expect.isTrue(matches.iterator.moveNext()); } testEmptyString() { String pattern = "foo"; String str = ""; Iterable matches = pattern.allMatches(str); - Expect.isFalse(matches.iterator().hasNext); + Expect.isFalse(matches.iterator.moveNext()); } testEmptyPatternAndString() { String pattern = ""; String str = ""; Iterable matches = pattern.allMatches(str); - Expect.isTrue(matches.iterator().hasNext); + Expect.isTrue(matches.iterator.moveNext()); } diff --git a/tests/corelib/string_replace_all_test.dart b/tests/corelib/string_replace_all_test.dart new file mode 100644 index 00000000000..ab246571eb0 --- /dev/null +++ b/tests/corelib/string_replace_all_test.dart @@ -0,0 +1,147 @@ +// Copyright (c) 2012, 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. + +testReplaceAll() { + Expect.equals( + "aXXcaXXdae", "abcabdae".replaceAll("b", "XX")); + + // Test with the replaced string at the begining. + Expect.equals( + "XXbcXXbdXXe", "abcabdae".replaceAll("a", "XX")); + + // Test with the replaced string at the end. + Expect.equals( + "abcabdaXX", "abcabdae".replaceAll("e", "XX")); + + // Test when there are no occurence of the string to replace. + Expect.equals( + "abcabdae", "abcabdae".replaceAll("f", "XX")); + + // Test when the string to change is the empty string. + Expect.equals("", "".replaceAll("from", "to")); + + // Test when the string to change is a substring of the string to + // replace. + Expect.equals("fro", "fro".replaceAll("from", "to")); + + // Test when the string to change is the replaced string. + Expect.equals("to", "from".replaceAll("from", "to")); + + // Test when matches are adjacent + Expect.equals("toto", "fromfrom".replaceAll("from", "to")); + + // Test when the string to change is the replacement string. + Expect.equals("to", "to".replaceAll("from", "to")); + + // Test replacing by the empty string. + Expect.equals( + "bcbde", "abcabdae".replaceAll("a", "")); + Expect.equals("AB", "AfromB".replaceAll("from", "")); + + // Test changing the empty string. + Expect.equals("to", "".replaceAll("", "to")); + + // Test replacing the empty string. + Expect.equals("toAtoBtoCto", "ABC".replaceAll("", "to")); +} + +testReplaceAllMapped() { + String mark(Match m) => "[${m[0]}]"; + Expect.equals( + "a[b]ca[b]dae", "abcabdae".replaceAllMapped("b", mark)); + + // Test with the replaced string at the begining. + Expect.equals( + "[a]bc[a]bd[a]e", "abcabdae".replaceAllMapped("a", mark)); + + // Test with the replaced string at the end. + Expect.equals( + "abcabda[e]", "abcabdae".replaceAllMapped("e", mark)); + + // Test when there are no occurence of the string to replace. + Expect.equals( + "abcabdae", "abcabdae".replaceAllMapped("f", mark)); + + // Test when the string to change is the empty string. + Expect.equals("", "".replaceAllMapped("from", mark)); + + // Test when the string to change is a substring of the string to + // replace. + Expect.equals("fro", "fro".replaceAllMapped("from", mark)); + + // Test when matches are adjacent + Expect.equals("[from][from]", "fromfrom".replaceAllMapped("from", mark)); + + // Test replacing by the empty string. + Expect.equals( + "bcbde", "abcabdae".replaceAllMapped("a", (m) => "")); + Expect.equals("AB", "AfromB".replaceAllMapped("from", (m) => "")); + + // Test changing the empty string. + Expect.equals("[]", "".replaceAllMapped("", mark)); + + // Test replacing the empty string. + Expect.equals("[]A[]B[]C[]", "ABC".replaceAllMapped("", mark)); +} + +testSplitMapJoin() { + String mark(Match m) => "[${m[0]}]"; + String wrap(String s) => "<${s}>"; + + Expect.equals( + "[b][b]", + "abcabdae".splitMapJoin("b", onMatch: mark, onNonMatch: wrap)); + + // Test with the replaced string at the begining. + Expect.equals( + "<>[a][a][a]", + "abcabdae".splitMapJoin("a", onMatch: mark, onNonMatch: wrap)); + + // Test with the replaced string at the end. + Expect.equals( + "[e]<>", + "abcabdae".splitMapJoin("e", onMatch: mark, onNonMatch: wrap)); + + // Test when there are no occurence of the string to replace. + Expect.equals( + "", + "abcabdae".splitMapJoin("f", onMatch: mark, onNonMatch: wrap)); + + // Test when the string to change is the empty string. + Expect.equals("<>", "".splitMapJoin("from", onMatch: mark, onNonMatch: wrap)); + + // Test when the string to change is a substring of the string to + // replace. + Expect.equals("", + "fro".splitMapJoin("from", onMatch: mark, onNonMatch: wrap)); + + // Test when matches are adjacent + Expect.equals("<>[from]<>[from]<>", + "fromfrom".splitMapJoin("from", onMatch: mark, onNonMatch: wrap)); + + // Test changing the empty string. + Expect.equals("<>[]<>", "".splitMapJoin("", onMatch: mark, onNonMatch: wrap)); + + // Test replacing the empty string. + Expect.equals("<>[][][][]<>", "ABC".splitMapJoin("", onMatch: mark, + onNonMatch: wrap)); + + // Test with only onMatch. + Expect.equals( + "[a]bc[a]bd[a]e", + "abcabdae".splitMapJoin("a", onMatch: mark)); + + + // Test with only onNonMatch + Expect.equals( + "<>aaa", + "abcabdae".splitMapJoin("a", onNonMatch: wrap)); + +} + +main() { + testReplaceAll(); + testReplaceAllMapped(); + testSplitMapJoin(); +} diff --git a/tests/corelib/string_slice_test.dart b/tests/corelib/string_slice_test.dart new file mode 100644 index 00000000000..5f0f4a3fd55 --- /dev/null +++ b/tests/corelib/string_slice_test.dart @@ -0,0 +1,93 @@ +// Copyright (c) 2012, 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. + +// Short string. +var s = "0123456789"; +// Long string. +var l = "$s$s$s$s$s$s$s$s$s$s"; +// Very long string. +var v = "$l$l$l$l$l$l$l$l$l$l"; + + +testSliceSuccess() { + // Test different ways to get the same slice from a string. + testSlice(String string, int start, int end) { + int length = string.length; + String expect = string.substring(start, end); + Expect.equals(expect, string.slice(start, end), "#${length}[$start:$end]"); + if (start < length) { + // If start == length, there is no negative representation of the position. + Expect.equals(expect, string.slice(start - length, end), + "#${length}[${start - length}:$end]"); + } + if (end < length) { + Expect.equals(expect, string.slice(start, end - length), + "#${length}[$start:${end - length}]"); + Expect.equals(expect, string.slice(start - length, end - length), + "#${length}[${start-length}:${end-length}]"); + } else { + Expect.equals(expect, string.slice(start), + "#${length}[$start]"); + if (start < length) { + Expect.equals(expect, string.slice(start - length), + "#${length}[${start-length}]"); + if (start == 0) { + Expect.equals(string, string.slice(), "#$length[:]"); + } + } + } + } + + testSliceCombinations(String string) { + int length = string.length; + List positions = [0, 1, string.length >> 1, length - 1, length]; + for (int i = 0; i < positions.length; i++) { + for (int j = i; j < positions.length; j++) { + testSlice(string, positions[i], positions[j]); + } + } + } + + testSliceCombinations(s); + testSliceCombinations(l); + testSliceCombinations(v); +} + +testSliceError() { + function expectRangeError(void thunk()) { + Expect.throws(thunk, (e) => e is RangeError); + }; + function expectArgumentError(void thunk()) { + Expect.throws(thunk, (e) => e is ArgumentError); + }; + function badType(void thunk()) { + bool checkedMode = false; + assert(checkedMode = true); + Expect.throws(thunk, + (e) => checkedMode ? e is TypeError : e is ArgumentError); + } + + // Invalid start: + expectRangeError(() => s.slice(11)); + expectRangeError(() => s.slice(-11)); + // Invalid end: + expectRangeError(() => s.slice(0, 11)); + expectRangeError(() => s.slice(0, -11)); + // Non-int: + badType(() => s.slice(1.5)); + badType(() => s.slice(0, 1.5)); + badType(() => s.slice("1")); + badType(() => s.slice(0, "1")); + // Bad order: + expectArgumentError(() => s.slice(5, 4)); + expectArgumentError(() => s.slice(-5, 4)); + expectArgumentError(() => s.slice(5, -6)); + expectArgumentError(() => s.slice(-5, -6)); +} + + +main() { + testSliceSuccess(); + testSliceError(); +} diff --git a/tests/corelib/strings_test.dart b/tests/corelib/strings_test.dart index 060bbfa0756..ef1766359f2 100644 --- a/tests/corelib/strings_test.dart +++ b/tests/corelib/strings_test.dart @@ -13,7 +13,7 @@ class StringsTest { } static testCreation() { String s = "Hello"; - List l = new List(s.length); + List l = new List.fixedLength(s.length); for (int i = 0; i < l.length; i++) { l[i] = s.charCodeAt(i); } diff --git a/tests/html/documentfragment_test.dart b/tests/html/documentfragment_test.dart index 257f9c612d2..0cf56268f83 100644 --- a/tests/html/documentfragment_test.dart +++ b/tests/html/documentfragment_test.dart @@ -14,7 +14,7 @@ main() { var isAnchorElement = predicate((x) => x is AnchorElement, 'is an AnchorElement'); - Collection _nodeStrings(Collection input) { + List _nodeStrings(Iterable input) { var out = new List(); for (Node n in input) { if (n is Element) { @@ -166,9 +166,9 @@ main() { test('accessors are wrapped', () { init(); expect(children[0].tagName, "A"); - expect(_nodeStrings(children.filter((e) => e.tagName == "I")), ["I"]); + expect(_nodeStrings(children.where((e) => e.tagName == "I")), ["I"]); expect(children.every((e) => e is Element), isTrue); - expect(children.some((e) => e.tagName == "U"), isTrue); + expect(children.any((e) => e.tagName == "U"), isTrue); expect(children.isEmpty, isFalse); expect(children.length, 4); expect(children[2].tagName, "I"); diff --git a/tests/html/element_classes_test.dart b/tests/html/element_classes_test.dart index 2ef18ccfdc2..809ef470450 100644 --- a/tests/html/element_classes_test.dart +++ b/tests/html/element_classes_test.dart @@ -66,13 +66,13 @@ main() { expect(classes, unorderedEquals(['foo', 'bar', 'baz'])); }); - test('map', () { - expect(makeClassSet().map((c) => c.toUpperCase()), + test('mappedBy', () { + expect(makeClassSet().mappedBy((c) => c.toUpperCase()).toList(), unorderedEquals(['FOO', 'BAR', 'BAZ'])); }); - test('filter', () { - expect(makeClassSet().filter((c) => c.contains('a')), + test('where', () { + expect(makeClassSet().where((c) => c.contains('a')).toSet(), unorderedEquals(['bar', 'baz'])); }); @@ -81,9 +81,9 @@ main() { expect(makeClassSet().every((c) => c.contains('a')), isFalse); }); - test('some', () { - expect(makeClassSet().some((c) => c.contains('a')), isTrue); - expect(makeClassSet().some((c) => c is num), isFalse); + test('any', () { + expect(makeClassSet().any((c) => c.contains('a')), isTrue); + expect(makeClassSet().any((c) => c is num), isFalse); }); test('isEmpty', () { diff --git a/tests/html/element_test.dart b/tests/html/element_test.dart index 63b586733ea..d9916ba24ca 100644 --- a/tests/html/element_test.dart +++ b/tests/html/element_test.dart @@ -368,9 +368,9 @@ main() { expect(els[2], isInputElement); }); - test('filter', () { + test('where', () { var filtered = makeElementWithChildren().children. - filter((n) => n is ImageElement); + where((n) => n is ImageElement); expect(1, filtered.length); expect(filtered[0], isImageElement); expect(filtered, isElementList); @@ -382,10 +382,10 @@ main() { expect(el.children.every((n) => n is InputElement), isFalse); }); - test('some', () { + test('any', () { var el = makeElementWithChildren(); - expect(el.children.some((n) => n is InputElement), isTrue); - expect(el.children.some((n) => n is svg.SvgElement), isFalse); + expect(el.children.any((n) => n is InputElement), isTrue); + expect(el.children.any((n) => n is svg.SvgElement), isFalse); }); test('isEmpty', () { @@ -506,13 +506,13 @@ main() { expect(els[2], isHRElement); }); - test('map', () { - var texts = getQueryAll().map((el) => el.text); + test('mappedBy', () { + var texts = getQueryAll().mappedBy((el) => el.text).toList(); expect(texts, equals(['Dart!', 'Hello', ''])); }); - test('filter', () { - var filtered = getQueryAll().filter((n) => n is SpanElement); + test('where', () { + var filtered = getQueryAll().where((n) => n is SpanElement).toList(); expect(filtered.length, 1); expect(filtered[0], isSpanElement); expect(filtered, isElementList); @@ -524,10 +524,10 @@ main() { expect(el.every((n) => n is SpanElement), isFalse); }); - test('some', () { + test('any', () { var el = getQueryAll(); - expect(el.some((n) => n is SpanElement), isTrue); - expect(el.some((n) => n is svg.SvgElement), isFalse); + expect(el.any((n) => n is SpanElement), isTrue); + expect(el.any((n) => n is svg.SvgElement), isFalse); }); test('isEmpty', () { @@ -590,8 +590,8 @@ main() { group('_ElementList', () { List makeElList() => makeElementWithChildren().children; - test('filter', () { - var filtered = makeElList().filter((n) => n is ImageElement); + test('where', () { + var filtered = makeElList().where((n) => n is ImageElement); expect(filtered.length, 1); expect(filtered[0], isImageElement); expect(filtered, isElementList); diff --git a/tests/html/htmlcollection_test.dart b/tests/html/htmlcollection_test.dart index cf7f1848bf7..e5e20cd8b8b 100644 --- a/tests/html/htmlcollection_test.dart +++ b/tests/html/htmlcollection_test.dart @@ -85,12 +85,12 @@ main() { expect(someChecked.length, 4); expect(noneChecked.length, 4); - expect(eachChecked.some((x) => x.checked), isTrue); - expect(eachChecked.some((x) => !x.checked), isFalse); - expect(someChecked.some((x) => x.checked), isTrue); - expect(someChecked.some((x) => !x.checked), isTrue); - expect(noneChecked.some((x) => x.checked), isFalse); - expect(noneChecked.some((x) => !x.checked), isTrue); + expect(eachChecked.any((x) => x.checked), isTrue); + expect(eachChecked.any((x) => !x.checked), isFalse); + expect(someChecked.any((x) => x.checked), isTrue); + expect(someChecked.any((x) => !x.checked), isTrue); + expect(noneChecked.any((x) => x.checked), isFalse); + expect(noneChecked.any((x) => !x.checked), isTrue); root.remove(); }); @@ -110,12 +110,12 @@ main() { expect(someChecked.length, 4); expect(noneChecked.length, 4); - expect(eachChecked.filter((x) => x.checked).length, 4); - expect(eachChecked.filter((x) => !x.checked).length, 0); - expect(someChecked.filter((x) => x.checked).length, 2); - expect(someChecked.filter((x) => !x.checked).length, 2); - expect(noneChecked.filter((x) => x.checked).length, 0); - expect(noneChecked.filter((x) => !x.checked).length, 4); + expect(eachChecked.where((x) => x.checked).length, 4); + expect(eachChecked.where((x) => !x.checked).length, 0); + expect(someChecked.where((x) => x.checked).length, 2); + expect(someChecked.where((x) => !x.checked).length, 2); + expect(noneChecked.where((x) => x.checked).length, 0); + expect(noneChecked.where((x) => !x.checked).length, 4); root.remove(); }); diff --git a/tests/html/isolates_test.dart b/tests/html/isolates_test.dart index 76e465bb466..608593f93fa 100644 --- a/tests/html/isolates_test.dart +++ b/tests/html/isolates_test.dart @@ -20,7 +20,7 @@ void isolateEntry() { } // Check that JSON library was loaded to isolate. - JSON.stringify([1, 2, 3]); + stringify([1, 2, 3]); isolate.port.receive((message, replyTo) { replyTo.send(responseFor(message), null); diff --git a/tests/html/js_interop_1_test.dart b/tests/html/js_interop_1_test.dart index 168294f8540..3d63ac1be7b 100644 --- a/tests/html/js_interop_1_test.dart +++ b/tests/html/js_interop_1_test.dart @@ -6,7 +6,6 @@ library JsInterop1Test; import '../../pkg/unittest/lib/unittest.dart'; import '../../pkg/unittest/lib/html_config.dart'; import 'dart:html'; -import 'dart:json'; injectSource(code) { final script = new ScriptElement(); diff --git a/tests/html/localstorage_test.dart b/tests/html/localstorage_test.dart index ff9a7a3fcc2..f2823a2059e 100644 --- a/tests/html/localstorage_test.dart +++ b/tests/html/localstorage_test.dart @@ -85,12 +85,12 @@ main() { }); testWithLocalStorage('getKeys', () { - expect(window.localStorage.keys, + expect(window.localStorage.keys.toList(), unorderedEquals(['key1', 'key2', 'key3'])); }); testWithLocalStorage('getVals', () { - expect(window.localStorage.values, + expect(window.localStorage.values.toList(), unorderedEquals(['val1', 'val2', 'val3'])); }); diff --git a/tests/html/native_gc_test.dart b/tests/html/native_gc_test.dart index fe27e0bb3c7..87251be4c19 100644 --- a/tests/html/native_gc_test.dart +++ b/tests/html/native_gc_test.dart @@ -14,7 +14,7 @@ main() { for (int i = 0; i < M; ++i) { // This memory should be freed when the listener below is // collected. - List l = new List(N); + List l = new List.fixedLength(N); // Record the iteration number. l[N - 1] = i; @@ -47,7 +47,7 @@ main() { } void triggerMajorGC() { - List list = new List(1000000); + List list = new List.fixedLength(1000000); Element div = new DivElement(); div.on.click.add((e) => print(list[0])); } diff --git a/tests/html/node_test.dart b/tests/html/node_test.dart index 5a406cf6d4d..d9cfe24a661 100644 --- a/tests/html/node_test.dart +++ b/tests/html/node_test.dart @@ -78,8 +78,9 @@ main() { expect(nodes[2], isComment); }); - test('filter', () { - var filtered = makeNodeWithChildren().nodes.filter((n) => n is BRElement); + test('where', () { + var filtered = + makeNodeWithChildren().nodes.where((n) => n is BRElement).toList(); expect(filtered.length, 1); expect(filtered[0], isBRElement); expect(filtered, isNodeList); @@ -91,10 +92,10 @@ main() { expect(node.nodes.every((n) => n is Comment), isFalse); }); - test('some', () { + test('any', () { var node = makeNodeWithChildren(); - expect(node.nodes.some((n) => n is Comment), isTrue); - expect(node.nodes.some((n) => n is svg.SvgElement), isFalse); + expect(node.nodes.any((n) => n is Comment), isTrue); + expect(node.nodes.any((n) => n is svg.SvgElement), isFalse); }); test('isEmpty', () { @@ -182,15 +183,15 @@ main() { group('_NodeList', () { List makeNodeList() => - makeNodeWithChildren().nodes.filter((_) => true); + makeNodeWithChildren().nodes.where((_) => true).toList(); test('first', () { var nodes = makeNodeList(); expect(nodes.first, isText); }); - test('filter', () { - var filtered = makeNodeList().filter((n) => n is BRElement); + test('where', () { + var filtered = makeNodeList().where((n) => n is BRElement).toList(); expect(filtered.length, 1); expect(filtered[0], isBRElement); expect(filtered, isNodeList); diff --git a/tests/html/queryall_test.dart b/tests/html/queryall_test.dart index 2d3fe958352..6ebce45d7cb 100644 --- a/tests/html/queryall_test.dart +++ b/tests/html/queryall_test.dart @@ -59,9 +59,9 @@ main() { } }); - test('queryAll-filter', () { + test('queryAll-where', () { List all = queryAll('*'); - List canvases = all.filter((e) => e is CanvasElement); + Iterable canvases = all.where((e) => e is CanvasElement); for (var e in canvases) { expect(e is CanvasElement, isTrue); } diff --git a/tests/html/typed_arrays_5_test.dart b/tests/html/typed_arrays_5_test.dart index d4da175c0c5..f755d3185af 100644 --- a/tests/html/typed_arrays_5_test.dart +++ b/tests/html/typed_arrays_5_test.dart @@ -21,7 +21,7 @@ main() { a[i] = i; } - expect(a.filter((x) => x >= 1000).length, equals(24)); + expect(a.where((x) => x >= 1000).length, equals(24)); }); test('filter_typed', () { @@ -30,7 +30,7 @@ main() { a[i] = i; } - expect(a.filter((x) => x >= 1000).length, equals(24)); + expect(a.where((x) => x >= 1000).length, equals(24)); }); test('contains', () { diff --git a/tests/html/websql_test.dart b/tests/html/websql_test.dart index 5bbf6e57499..a4416ce87c6 100644 --- a/tests/html/websql_test.dart +++ b/tests/html/websql_test.dart @@ -99,10 +99,10 @@ main() { createTransaction(db) // Attempt to clear out any tables which may be lurking from previous // runs. - .chain(dropTable(tableName, true)) - .chain(createTable(tableName, columnName)) - .chain(insert(tableName, columnName, 'Some text data')) - .chain(queryTable(tableName, (resultSet) { + .then(dropTable(tableName, true)) + .then(createTable(tableName, columnName)) + .then(insert(tableName, columnName, 'Some text data')) + .then(queryTable(tableName, (resultSet) { guardAsync(() { expect(resultSet.rows.length, 1); var row = resultSet.rows.item(0); @@ -110,7 +110,7 @@ main() { expect(row[columnName], 'Some text data'); }); })) - .chain(dropTable(tableName)) + .then(dropTable(tableName)) .then(expectAsync1((tx) {})); }); } diff --git a/tests/html/xhr_cross_origin_test.dart b/tests/html/xhr_cross_origin_test.dart index d39af2c85e3..22077f5b91a 100644 --- a/tests/html/xhr_cross_origin_test.dart +++ b/tests/html/xhr_cross_origin_test.dart @@ -6,7 +6,7 @@ library XHRCrossOriginTest; import '../../pkg/unittest/lib/unittest.dart'; import '../../pkg/unittest/lib/html_config.dart'; import 'dart:html'; -import 'dart:json'; +import 'dart:json' as json; main() { useHtmlConfiguration(); @@ -23,7 +23,7 @@ main() { xhr.on.readyStateChange.add((e) { guardAsync(() { if (xhr.readyState == HttpRequest.DONE) { - validate(JSON.parse(xhr.response)); + validate(json.parse(xhr.response)); } }); }); @@ -33,7 +33,7 @@ main() { test('XHR.get Cross-domain', () { var url = "http://localhost:9876/tests/html/xhr_cross_origin_data.txt"; new HttpRequest.get(url, expectAsync1((xhr) { - var data = JSON.parse(xhr.response); + var data = json.parse(xhr.response); expect(data, contains('feed')); expect(data['feed'], contains('entry')); expect(data, isMap); diff --git a/tests/html/xhr_test.dart b/tests/html/xhr_test.dart index b5ea6c1cb0a..4d0ac069923 100644 --- a/tests/html/xhr_test.dart +++ b/tests/html/xhr_test.dart @@ -6,7 +6,6 @@ library XHRTest; import '../../pkg/unittest/lib/unittest.dart'; import '../../pkg/unittest/lib/html_config.dart'; import 'dart:html'; -import 'dart:json'; main() { useHtmlConfiguration(); diff --git a/tests/html/xmldocument_test.dart b/tests/html/xmldocument_test.dart index 35666e6a89a..9dc830bc1ac 100644 --- a/tests/html/xmldocument_test.dart +++ b/tests/html/xmldocument_test.dart @@ -41,7 +41,8 @@ main() { group('children', () { test('filters out non-element nodes', () { final doc = new XMLDocument.xml("123"); - expect(doc.children.map((e) => e.tagName), ["a", "b", "c", "d"]); + expect(doc.children.mappedBy((e) => e.tagName).toList(), + ["a", "b", "c", "d"]); }); test('overwrites nodes when set', () { @@ -101,13 +102,13 @@ main() { expect(classes, unorderedEquals(['foo', 'bar', 'baz'])); }); - test('map', () { - expect(makeClassSet().map((c) => c.toUpperCase()), + test('mappedBy', () { + expect(makeClassSet().mappedBy((c) => c.toUpperCase()).toList(), unorderedEquals(['FOO', 'BAR', 'BAZ'])); }); - test('filter', () { - expect(makeClassSet().filter((c) => c.contains('a')), + test('where', () { + expect(makeClassSet().where((c) => c.contains('a')).toSet(), unorderedEquals(['bar', 'baz'])); }); @@ -116,9 +117,9 @@ main() { expect(makeClassSet().every((c) => c.contains('a')), isFalse); }); - test('some', () { - expect(makeClassSet().some((c) => c.contains('a')), isTrue); - expect(makeClassSet().some((c) => c is num), isFalse); + test('any', () { + expect(makeClassSet().any((c) => c.contains('a')), isTrue); + expect(makeClassSet().any((c) => c is num), isFalse); }); test('isEmpty', () { @@ -427,7 +428,7 @@ main() { test('queryAll', () { final doc = new XMLDocument.xml( ""); - expect(doc.queryAll('foo').map((e) => e.id), ['f1', 'f2']); + expect(doc.queryAll('foo').mappedBy((e) => e.id).toList(), ['f1', 'f2']); expect(doc.queryAll('baz'), []); }); diff --git a/tests/html/xmlelement_test.dart b/tests/html/xmlelement_test.dart index 94cfb1a2284..61dba0cb271 100644 --- a/tests/html/xmlelement_test.dart +++ b/tests/html/xmlelement_test.dart @@ -57,7 +57,8 @@ main() { group('children', () { test('filters out non-element nodes', () { final el = new XMLElement.xml("123"); - expect(el.children.map((e) => e.tagName), ["a", "b", "c", "d"]); + expect(el.children.mappedBy((e) => e.tagName).toList(), + ["a", "b", "c", "d"]); }); test('overwrites nodes when set', () { @@ -114,13 +115,13 @@ main() { expect(classes, unorderedEquals(['foo', 'bar', 'baz'])); }); - test('map', () { - expect(makeClassSet().map((c) => c.toUpperCase()), + test('mappedBy', () { + expect(makeClassSet().mappedBy((c) => c.toUpperCase()).toList(), unorderedEquals(['FOO', 'BAR', 'BAZ'])); }); - test('filter', () { - expect(makeClassSet().filter((c) => c.contains('a')), + test('where', () { + expect(makeClassSet().where((c) => c.contains('a')).toSet(), unorderedEquals(['bar', 'baz'])); }); @@ -129,9 +130,9 @@ main() { expect(makeClassSet().every((c) => c.contains('a')), isFalse); }); - test('some', () { - expect(makeClassSet().some((c) => c.contains('a')), isTrue); - expect(makeClassSet().some((c) => c is num), isFalse); + test('any', () { + expect(makeClassSet().any((c) => c.contains('a')), isTrue); + expect(makeClassSet().any((c) => c is num), isFalse); }); test('isEmpty', () { @@ -417,7 +418,7 @@ main() { test('queryAll', () { final el = new XMLElement.xml( ""); - expect(el.queryAll('foo').map((e) => e.id), ['f1', 'f2']); + expect(el.queryAll('foo').mappedBy((e) => e.id).toList(), ['f1', 'f2']); expect(el.queryAll('baz'), []); }); diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status index 3e6af4a2585..edf1b8b8af7 100644 --- a/tests/isolate/isolate.status +++ b/tests/isolate/isolate.status @@ -109,3 +109,7 @@ timer_test: Fail,OK # Needs Timer to run. [ $compiler == dart2dart ] # Skip until we stabilize language tests. *: Skip + +# TODO(ajohnsen): Fix this as part of library changes. +[ $compiler == none ] +isolate_negative_test: Skip # Bug 6890 diff --git a/tests/isolate/mandel_isolate_test.dart b/tests/isolate/mandel_isolate_test.dart index 7074ee73152..292d6d63f4e 100644 --- a/tests/isolate/mandel_isolate_test.dart +++ b/tests/isolate/mandel_isolate_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. library MandelIsolateTest; +import 'dart:async'; import 'dart:isolate'; import 'dart:math'; import '../../pkg/unittest/lib/unittest.dart'; @@ -26,7 +27,7 @@ class MandelbrotState { MandelbrotState() { _result = new List>(N); - _lineProcessedBy = new List(N); + _lineProcessedBy = new List.fixedLength(N); _sent = 0; _missing = N; _validated = new Completer(); @@ -106,7 +107,7 @@ class LineProcessorClient { List processLine(int y) { double inverseN = 2.0 / N; double Civ = y * inverseN - 1.0; - List result = new List(N); + List result = new List.fixedLength(N); for (int x = 0; x < N; x++) { double Crv = x * inverseN - 1.5; diff --git a/tests/isolate/message_test.dart b/tests/isolate/message_test.dart index ee00de52c56..a281d81f22a 100644 --- a/tests/isolate/message_test.dart +++ b/tests/isolate/message_test.dart @@ -100,7 +100,7 @@ main() { List local_list1 = ["Hello", "World", "Hello", 0xffffffffff]; List local_list2 = [null, local_list1, local_list1 ]; List local_list3 = [local_list2, 2.0, true, false, 0xffffffffff]; - List sendObject = new List(5); + List sendObject = new List.fixedLength(5); sendObject[0] = local_list1; sendObject[1] = sendObject; sendObject[2] = local_list2; diff --git a/tests/isolate/multiple_timer_test.dart b/tests/isolate/multiple_timer_test.dart index d1da947c3d2..15e16edc92f 100644 --- a/tests/isolate/multiple_timer_test.dart +++ b/tests/isolate/multiple_timer_test.dart @@ -4,7 +4,7 @@ library multiple_timer_test; -import 'dart:isolate'; +import 'dart:async'; import '../../pkg/unittest/lib/unittest.dart'; const int TIMEOUT1 = 1000; @@ -49,7 +49,7 @@ main() { _message++; } - _order = new List(4); + _order = new List.fixedLength(4); _order[0] = 2; _order[1] = 0; _order[2] = 3; diff --git a/tests/isolate/stream_mangling_test.dart b/tests/isolate/stream_mangling_test.dart new file mode 100644 index 00000000000..fbc56f6d539 --- /dev/null +++ b/tests/isolate/stream_mangling_test.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2012, 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. + +import 'dart:isolate'; +import '../../pkg/unittest/lib/unittest.dart'; + +main() { + test("Self referencing arrays serialize correctly", () { + var messageBox = new MessageBox(); + var stream = messageBox.stream; + var sink = messageBox.sink; + var nested = []; + nested.add(nested); + Expect.identical(nested, nested[0]); + stream.listen(expectAsync1((data) { + Expect.isFalse(identical(nested, data)); + Expect.isTrue(data is List); + Expect.equals(1, data.length); + Expect.identical(data, data[0]); + stream.close(); + })); + sink.add(nested); + }); + + test("Self referencing arrays serialize correctly 2", () { + var messageBox = new MessageBox(); + var stream = messageBox.stream; + var sink = messageBox.sink; + var nested = [0, 1]; + nested.add(nested); + nested.add(3); + nested.add(4); + Expect.identical(nested, nested[2]); + stream.listen(expectAsync1((data) { + Expect.isFalse(identical(nested, data)); + Expect.isTrue(data is List); + Expect.equals(5, data.length); + Expect.identical(data, data[2]); + Expect.equals(0, data[0]); + Expect.equals(1, data[1]); + Expect.equals(3, data[3]); + Expect.equals(4, data[4]); + stream.close(); + })); + sink.add(nested); + }); + + test("Self referencing arrays serialize correctly 3", () { + var messageBox = new MessageBox(); + var stream = messageBox.stream; + var sink = messageBox.sink; + var nested = [[[[[0, 1]]]]]; + nested.add(nested); + nested[0][0][0][0].add(nested); + nested.add(3); + nested.add(4); + Expect.identical(nested, nested[0][0][0][0][2]); + stream.listen(expectAsync1((data) { + Expect.isFalse(identical(nested, data)); + Expect.isTrue(data is List); + Expect.equals(4, data.length); + Expect.equals(1, data[0].length); + Expect.equals(1, data[0][0].length); + Expect.equals(1, data[0][0][0].length); + Expect.equals(3, data[0][0][0][0].length); + Expect.identical(data, data[0][0][0][0][2]); + Expect.identical(data, data[1]); + Expect.equals(3, data[2]); + Expect.equals(4, data[3]); + stream.close(); + })); + sink.add(nested); + }); + + test("Self referencing maps serialize correctly", () { + var messageBox = new MessageBox(); + var stream = messageBox.stream; + var sink = messageBox.sink; + var nested = {}; + nested["foo"] = nested; + Expect.identical(nested, nested["foo"]); + stream.listen(expectAsync1((data) { + Expect.isFalse(identical(nested, data)); + Expect.isTrue(data is Map); + Expect.equals(1, data.length); + Expect.identical(data, data["foo"]); + stream.close(); + })); + sink.add(nested); + }); + + test("Sending of IsolateSinks", () { + // TODO(floitsch): add test. + }); + + test("Sending of IsolateSinks in complicated structures", () { + // TODO(floitsch): add test. + }); +} \ No newline at end of file diff --git a/tests/isolate/timer_cancel1_test.dart b/tests/isolate/timer_cancel1_test.dart index c4d42770e0a..efcbbe8cb18 100644 --- a/tests/isolate/timer_cancel1_test.dart +++ b/tests/isolate/timer_cancel1_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. library timer_cancel1_test; -import 'dart:isolate'; +import 'dart:async'; import '../../pkg/unittest/lib/unittest.dart'; main() { diff --git a/tests/isolate/timer_cancel2_test.dart b/tests/isolate/timer_cancel2_test.dart index f01a8ccd393..a7ea99760c9 100644 --- a/tests/isolate/timer_cancel2_test.dart +++ b/tests/isolate/timer_cancel2_test.dart @@ -4,7 +4,7 @@ library timer_cancel2_test; -import 'dart:isolate'; +import 'dart:async'; import '../../pkg/unittest/lib/unittest.dart'; main() { diff --git a/tests/isolate/timer_cancel_test.dart b/tests/isolate/timer_cancel_test.dart index 745a91b563e..d610fecbb4a 100644 --- a/tests/isolate/timer_cancel_test.dart +++ b/tests/isolate/timer_cancel_test.dart @@ -4,6 +4,7 @@ library timer_cancel_test; +import 'dart:async'; import 'dart:isolate'; import '../../pkg/unittest/lib/unittest.dart'; diff --git a/tests/isolate/timer_repeat_test.dart b/tests/isolate/timer_repeat_test.dart index 31653dc0a36..d13e9884f57 100644 --- a/tests/isolate/timer_repeat_test.dart +++ b/tests/isolate/timer_repeat_test.dart @@ -4,7 +4,7 @@ library timer_repeat_test; -import 'dart:isolate'; +import 'dart:async'; import '../../pkg/unittest/lib/unittest.dart'; const int TIMEOUT = 500; @@ -13,7 +13,7 @@ const int ITERATIONS = 5; Timer timer; int startTime; int iteration; - + void timeoutHandler(Timer timer) { int endTime = (new Date.now()).millisecondsSinceEpoch; iteration++; diff --git a/tests/isolate/timer_test.dart b/tests/isolate/timer_test.dart index 0ec4bf45024..86f6753e92d 100644 --- a/tests/isolate/timer_test.dart +++ b/tests/isolate/timer_test.dart @@ -4,7 +4,7 @@ library timer_test; -import 'dart:isolate'; +import 'dart:async'; import '../../pkg/unittest/lib/unittest.dart'; const int STARTTIMEOUT = 1050; diff --git a/tests/json/json_test.dart b/tests/json/json_test.dart index ef1c20e2dd3..5ec1c8386ad 100644 --- a/tests/json/json_test.dart +++ b/tests/json/json_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. library json_tests; -import 'dart:json'; +import 'dart:json' as json; import 'dart:html'; import '../../pkg/unittest/lib/unittest.dart'; import '../../pkg/unittest/lib/html_config.dart'; @@ -12,95 +12,95 @@ main() { useHtmlConfiguration(); test('Parse', () { // Scalars. - expect(JSON.parse(' 5 '), equals(5)); - expect(JSON.parse(' -42 '), equals(-42)); - expect(JSON.parse(' 3e0 '), equals(3)); - expect(JSON.parse(' 3.14 '), equals(3.14)); - expect(JSON.parse('true '), isTrue); - expect(JSON.parse(' false'), isFalse); - expect(JSON.parse(' null '), isNull); - expect(JSON.parse('\n\rnull\t'), isNull); - expect(JSON.parse(' "hi there\\" bob" '), equals('hi there" bob')); - expect(JSON.parse(' "" '), isEmpty); + expect(json.parse(' 5 '), equals(5)); + expect(json.parse(' -42 '), equals(-42)); + expect(json.parse(' 3e0 '), equals(3)); + expect(json.parse(' 3.14 '), equals(3.14)); + expect(json.parse('true '), isTrue); + expect(json.parse(' false'), isFalse); + expect(json.parse(' null '), isNull); + expect(json.parse('\n\rnull\t'), isNull); + expect(json.parse(' "hi there\\" bob" '), equals('hi there" bob')); + expect(json.parse(' "" '), isEmpty); // Lists. - expect(JSON.parse(' [] '), isEmpty); - expect(JSON.parse('[ ]'), isEmpty); - expect(JSON.parse(' [3, -4.5, true, "hi", false] '), + expect(json.parse(' [] '), isEmpty); + expect(json.parse('[ ]'), isEmpty); + expect(json.parse(' [3, -4.5, true, "hi", false] '), equals([3, -4.5, true, 'hi', false])); // Nulls are tricky. - expect(JSON.parse('[null]'), orderedEquals([null])); - expect(JSON.parse(' [3, -4.5, null, true, "hi", false] '), + expect(json.parse('[null]'), orderedEquals([null])); + expect(json.parse(' [3, -4.5, null, true, "hi", false] '), equals([3, -4.5, null, true, 'hi', false])); - expect(JSON.parse('[[null]]'), equals([[null]])); - expect(JSON.parse(' [ [3], [], [null], ["hi", true]] '), + expect(json.parse('[[null]]'), equals([[null]])); + expect(json.parse(' [ [3], [], [null], ["hi", true]] '), equals([[3], [], [null], ['hi', true]])); // Maps. - expect(JSON.parse(' {} '), isEmpty); - expect(JSON.parse('{ }'), isEmpty); + expect(json.parse(' {} '), isEmpty); + expect(json.parse('{ }'), isEmpty); - expect(JSON.parse( + expect(json.parse( ' {"x":3, "y": -4.5, "z" : "hi","u" : true, "v": false } '), equals({"x":3, "y": -4.5, "z" : "hi", "u" : true, "v": false })); - expect(JSON.parse(' {"x":3, "y": -4.5, "z" : "hi" } '), + expect(json.parse(' {"x":3, "y": -4.5, "z" : "hi" } '), equals({"x":3, "y": -4.5, "z" : "hi" })); - expect(JSON.parse(' {"y": -4.5, "z" : "hi" ,"x":3 } '), + expect(json.parse(' {"y": -4.5, "z" : "hi" ,"x":3 } '), equals({"y": -4.5, "z" : "hi" ,"x":3 })); - expect(JSON.parse('{ " hi bob " :3, "": 4.5}'), + expect(json.parse('{ " hi bob " :3, "": 4.5}'), equals({ " hi bob " :3, "": 4.5})); - expect(JSON.parse(' { "x" : { } } '), equals({ 'x' : {}})); - expect(JSON.parse('{"x":{}}'), equals({ 'x' : {}})); + expect(json.parse(' { "x" : { } } '), equals({ 'x' : {}})); + expect(json.parse('{"x":{}}'), equals({ 'x' : {}})); // Nulls are tricky. - expect(JSON.parse('{"w":null}'), equals({ 'w' : null})); + expect(json.parse('{"w":null}'), equals({ 'w' : null})); - expect(JSON.parse('{"x":{"w":null}}'), equals({"x":{"w":null}})); + expect(json.parse('{"x":{"w":null}}'), equals({"x":{"w":null}})); - expect(JSON.parse(' {"x":3, "y": -4.5, "z" : "hi",' + expect(json.parse(' {"x":3, "y": -4.5, "z" : "hi",' '"w":null, "u" : true, "v": false } '), equals({"x":3, "y": -4.5, "z" : "hi", "w":null, "u" : true, "v": false })); - expect(JSON.parse('{"x": {"a":3, "b": -4.5}, "y":[{}], ' + expect(json.parse('{"x": {"a":3, "b": -4.5}, "y":[{}], ' '"z":"hi","w":{"c":null,"d":true}, "v":null}'), equals({"x": {"a":3, "b": -4.5}, "y":[{}], "z":"hi","w":{"c":null,"d":true}, "v":null})); test('stringify', () { // Scalars. - expect(JSON.stringify(5), equals('5')); - expect(JSON.stringify(-42), equals('-42')); + expect(json.stringify(5), equals('5')); + expect(json.stringify(-42), equals('-42')); // Dart does not guarantee a formatting for doubles, // so reparse and compare to the original. validateRoundTrip(3.14); - expect(JSON.stringify(true), equals('true')); - expect(JSON.stringify(false), equals('false')); - expect(JSON.stringify(null), equals('null')); - expect(JSON.stringify(' hi there" bob '), equals('" hi there\\" bob "')); - expect(JSON.stringify('hi\\there'), equals('"hi\\\\there"')); + expect(json.stringify(true), equals('true')); + expect(json.stringify(false), equals('false')); + expect(json.stringify(null), equals('null')); + expect(json.stringify(' hi there" bob '), equals('" hi there\\" bob "')); + expect(json.stringify('hi\\there'), equals('"hi\\\\there"')); // TODO(devoncarew): these tests break the dartium build - //expect(JSON.stringify('hi\nthere'), equals('"hi\\nthere"')); - //expect(JSON.stringify('hi\r\nthere'), equals('"hi\\r\\nthere"')); - expect(JSON.stringify(''), equals('""')); + //expect(json.stringify('hi\nthere'), equals('"hi\\nthere"')); + //expect(json.stringify('hi\r\nthere'), equals('"hi\\r\\nthere"')); + expect(json.stringify(''), equals('""')); // Lists. - expect(JSON.stringify([]), equals('[]')); - expect(JSON.stringify(new List(0)), equals('[]')); - expect(JSON.stringify(new List(3)), equals('[null,null,null]')); + expect(json.stringify([]), equals('[]')); + expect(json.stringify(new List.fixedLength(0)), equals('[]')); + expect(json.stringify(new List.fixedLength(3)), equals('[null,null,null]')); validateRoundTrip([3, -4.5, null, true, 'hi', false]); - expect(JSON.stringify([[3], [], [null], ['hi', true]]), + expect(json.stringify([[3], [], [null], ['hi', true]]), equals('[[3],[],[null],["hi",true]]')); // Maps. - expect(JSON.stringify({}), equals('{}')); - expect(JSON.stringify(new Map()), equals('{}')); - expect(JSON.stringify({'x':{}}), equals('{"x":{}}')); - expect(JSON.stringify({'x':{'a':3}}), equals('{"x":{"a":3}}')); + expect(json.stringify({}), equals('{}')); + expect(json.stringify(new Map()), equals('{}')); + expect(json.stringify({'x':{}}), equals('{"x":{}}')); + expect(json.stringify({'x':{'a':3}}), equals('{"x":{"a":3}}')); // Dart does not guarantee an order on the keys // of a map literal, so reparse and compare to the original Map. @@ -112,17 +112,17 @@ main() { {'x':{'a':3, 'b':-4.5}, 'y':[{}], 'z':'hi', 'w':{'c':null, 'd':true}, 'v':null}); - expect(JSON.stringify(new ToJson(4)), "4"); - expect(JSON.stringify(new ToJson([4, "a"])), '[4,"a"]'); - expect(JSON.stringify(new ToJson([4, new ToJson({"x":42})])), + expect(json.stringify(new ToJson(4)), "4"); + expect(json.stringify(new ToJson([4, "a"])), '[4,"a"]'); + expect(json.stringify(new ToJson([4, new ToJson({"x":42})])), '[4,{"x":42}]'); Expect.throws(() { - JSON.stringify([new ToJson(new ToJson(4))]); + json.stringify([new ToJson(new ToJson(4))]); }); Expect.throws(() { - JSON.stringify([new Object()]); + json.stringify([new Object()]); }); }); @@ -132,7 +132,7 @@ main() { * Checks that we get an exception (rather than silently returning null) if * we try to stringify something that cannot be converted to json. */ - expect(() => JSON.stringify(new TestClass()), throws); + expect(() => json.stringify(new TestClass()), throws); }); }); } @@ -155,7 +155,7 @@ class ToJson { * back, and produce something equivalent to the argument. */ validateRoundTrip(expected) { - expect(JSON.parse(JSON.stringify(expected)), equals(expected)); + expect(json.parse(json.stringify(expected)), equals(expected)); } diff --git a/tests/language/arithmetic_test.dart b/tests/language/arithmetic_test.dart index 5c36ddfb988..eceb9a63386 100644 --- a/tests/language/arithmetic_test.dart +++ b/tests/language/arithmetic_test.dart @@ -10,7 +10,7 @@ class ArithmeticTest { static bool exceptionCaughtParseInt(String s) { try { - parseInt(s); + int.parse(s); return false; } on FormatException catch (e) { return true; @@ -19,20 +19,20 @@ class ArithmeticTest { static bool exceptionCaughtParseDouble(String s) { try { - parseDouble(s); + double.parse(s); return false; } on FormatException catch (e) { return true; } } - static bool toIntThrowsFormatException(String str) { + static bool toIntThrowsUnsupportedError(String str) { // No exception allowed for parse double. - double d = parseDouble(str); + double d = double.parse(str); try { var a = d.toInt(); return false; - } on FormatException catch (e) { + } on UnsupportedError catch (e) { return true; } } @@ -61,7 +61,7 @@ class ArithmeticTest { Expect.equals(26.0, a + b); Expect.equals(18.0, a - b); Expect.equals(88.0, a * b); - Expect.equals(5.0, a ~/ b); + Expect.equals(5, a ~/ b); Expect.equals(5.5, a / b); Expect.equals(2.0, a % b); Expect.equals(2.0, a.remainder(b)); @@ -71,7 +71,7 @@ class ArithmeticTest { Expect.equals(26.0, a + b); Expect.equals(18.0, a - b); Expect.equals(88.0, a * b); - Expect.equals(5.0, a ~/ b); + Expect.equals(5, a ~/ b); Expect.equals(5.5, a / b); Expect.equals(2.0, a % b); Expect.equals(2.0, a.remainder(b)); @@ -345,24 +345,24 @@ class ArithmeticTest { Expect.approxEquals(1.0, sin(3.14159265 / 2.0)); Expect.approxEquals(-1.0, cos(3.14159265)); - Expect.equals(12, parseInt("12")); - Expect.equals(-12, parseInt("-12")); + Expect.equals(12, int.parse("12")); + Expect.equals(-12, int.parse("-12")); Expect.equals(12345678901234567890, - parseInt("12345678901234567890")); + int.parse("12345678901234567890")); Expect.equals(-12345678901234567890, - parseInt("-12345678901234567890")); + int.parse("-12345678901234567890")); // Type checks. - { int i = parseInt("12"); } - { int i = parseInt("-12"); } - { int i = parseInt("12345678901234567890"); } - { int i = parseInt("-12345678901234567890"); } + { int i = int.parse("12"); } + { int i = int.parse("-12"); } + { int i = int.parse("12345678901234567890"); } + { int i = int.parse("-12345678901234567890"); } - Expect.equals(1.2, parseDouble("1.2")); - Expect.equals(-1.2, parseDouble("-1.2")); + Expect.equals(1.2, double.parse("1.2")); + Expect.equals(-1.2, double.parse("-1.2")); // Type checks. - { double d = parseDouble("1.2"); } - { double d = parseDouble("-1.2"); } - { double d = parseDouble("0"); } + { double d = double.parse("1.2"); } + { double d = double.parse("-1.2"); } + { double d = double.parse("0"); } // Random { @@ -377,25 +377,25 @@ class ArithmeticTest { Expect.equals(true, exceptionCaughtParseDouble("alpha")); Expect.equals(true, exceptionCaughtParseDouble("-alpha")); - Expect.equals(false, parseDouble("1.2").isNaN); - Expect.equals(false, parseDouble("1.2").isInfinite); + Expect.equals(false, double.parse("1.2").isNaN); + Expect.equals(false, double.parse("1.2").isInfinite); - Expect.equals(true, parseDouble("NaN").isNaN); - Expect.equals(true, parseDouble("Infinity").isInfinite); - Expect.equals(true, parseDouble("-Infinity").isInfinite); + Expect.equals(true, double.parse("NaN").isNaN); + Expect.equals(true, double.parse("Infinity").isInfinite); + Expect.equals(true, double.parse("-Infinity").isInfinite); - Expect.equals(false, parseDouble("NaN").isNegative); - Expect.equals(false, parseDouble("Infinity").isNegative); - Expect.equals(true, parseDouble("-Infinity").isNegative); + Expect.equals(false, double.parse("NaN").isNegative); + Expect.equals(false, double.parse("Infinity").isNegative); + Expect.equals(true, double.parse("-Infinity").isNegative); - Expect.equals("NaN", parseDouble("NaN").toString()); - Expect.equals("Infinity", parseDouble("Infinity").toString()); - Expect.equals("-Infinity", parseDouble("-Infinity").toString()); + Expect.equals("NaN", double.parse("NaN").toString()); + Expect.equals("Infinity", double.parse("Infinity").toString()); + Expect.equals("-Infinity", double.parse("-Infinity").toString()); - Expect.equals(false, toIntThrowsFormatException("1.2")); - Expect.equals(true, toIntThrowsFormatException("Infinity")); - Expect.equals(true, toIntThrowsFormatException("-Infinity")); - Expect.equals(true, toIntThrowsFormatException("NaN")); + Expect.equals(false, toIntThrowsUnsupportedError("1.2")); + Expect.equals(true, toIntThrowsUnsupportedError("Infinity")); + Expect.equals(true, toIntThrowsUnsupportedError("-Infinity")); + Expect.equals(true, toIntThrowsUnsupportedError("NaN")); // Min/max Expect.equals(1, min(1, 12)); diff --git a/tests/language/bailout4_test.dart b/tests/language/bailout4_test.dart index 52e9713d615..0bb3edf74cd 100644 --- a/tests/language/bailout4_test.dart +++ b/tests/language/bailout4_test.dart @@ -10,7 +10,7 @@ class A { } var a = new A(); -var b = new List(4); +var b = new List.fixedLength(4); int count = 0; main() { diff --git a/tests/language/compile_time_constant_a_test.dart b/tests/language/compile_time_constant_a_test.dart index 254106497a8..73ff7de6ab5 100644 --- a/tests/language/compile_time_constant_a_test.dart +++ b/tests/language/compile_time_constant_a_test.dart @@ -15,8 +15,8 @@ bool isUnsupportedError(o) => o is UnsupportedError; main() { Expect.equals(499, m1['a']); Expect.equals(null, m1['b']); - Expect.listEquals(['a'], m1.keys); - Expect.listEquals([499], m1.values); + Expect.listEquals(['a'], m1.keys.toList()); + Expect.listEquals([499], m1.values.toList()); Expect.isTrue(m1.containsKey('a')); Expect.isFalse(m1.containsKey('toString')); Expect.isTrue(m1.containsValue(499)); @@ -43,8 +43,8 @@ main() { Expect.equals(499, m2['a']); Expect.equals(42, m2['b']); Expect.equals(null, m2['c']); - Expect.listEquals(['a', 'b'], m2.keys); - Expect.listEquals([499, 42], m2.values); + Expect.listEquals(['a', 'b'], m2.keys.toList()); + Expect.listEquals([499, 42], m2.values.toList()); Expect.isTrue(m2.containsKey('a')); Expect.isTrue(m2.containsKey('b')); Expect.isFalse(m2.containsKey('toString')); @@ -76,8 +76,8 @@ main() { Expect.identical(m3['m1'], m1); Expect.identical(m3['m2'], m2); - Expect.listEquals(['z', 'a', 'm'], m4.keys); - Expect.listEquals([9, 8, 7], m4.values); + Expect.listEquals(['z', 'a', 'm'], m4.keys.toList()); + Expect.listEquals([9, 8, 7], m4.values.toList()); seenKeys = []; seenValues = []; m4.forEach((key, value) { @@ -96,8 +96,8 @@ main() { Expect.isTrue(m7.isEmpty); Expect.equals(0, m7.length); Expect.equals(null, m7['b']); - Expect.listEquals([], m7.keys); - Expect.listEquals([], m7.values); + Expect.listEquals([], m7.keys.toList()); + Expect.listEquals([], m7.values.toList()); Expect.isFalse(m7.containsKey('a')); Expect.isFalse(m7.containsKey('toString')); Expect.isFalse(m7.containsValue(499)); diff --git a/tests/language/compile_time_constant_b_test.dart b/tests/language/compile_time_constant_b_test.dart index a2739032cf6..49e48f9a92e 100644 --- a/tests/language/compile_time_constant_b_test.dart +++ b/tests/language/compile_time_constant_b_test.dart @@ -11,8 +11,8 @@ bool isUnsupportedError(o) => o is UnsupportedError; main() { Expect.equals(499, m1['__proto__']); Expect.equals(null, m1['b']); - Expect.listEquals(['__proto__'], m1.keys); - Expect.listEquals([499], m1.values); + Expect.listEquals(['__proto__'], m1.keys.toList()); + Expect.listEquals([499], m1.values.toList()); Expect.isTrue(m1.containsKey('__proto__')); Expect.isFalse(m1.containsKey('toString')); Expect.isTrue(m1.containsValue(499)); @@ -40,8 +40,8 @@ main() { Expect.equals(42, m2['b']); Expect.equals(null, m2['c']); Expect.equals(null, m2['__proto__']); - Expect.listEquals(['a', 'b'], m2.keys); - Expect.listEquals([499, 42], m2.values); + Expect.listEquals(['a', 'b'], m2.keys.toList()); + Expect.listEquals([499, 42], m2.values.toList()); Expect.isTrue(m2.containsKey('a')); Expect.isTrue(m2.containsKey('b')); Expect.isFalse(m2.containsKey('toString')); diff --git a/tests/language/compound_assignment_operator_test.dart b/tests/language/compound_assignment_operator_test.dart index e875af19bb5..52c52898f57 100644 --- a/tests/language/compound_assignment_operator_test.dart +++ b/tests/language/compound_assignment_operator_test.dart @@ -5,7 +5,7 @@ class Indexed { - Indexed() : _f = new List(10), count = 0 { + Indexed() : _f = new List.fixedLength(10), count = 0 { _f[0] = 100; _f[1] = 200; } diff --git a/tests/language/const_list_test.dart b/tests/language/const_list_test.dart index e05f7a779bf..4422efb9175 100644 --- a/tests/language/const_list_test.dart +++ b/tests/language/const_list_test.dart @@ -5,8 +5,8 @@ class ConstListTest { static testMain() { - List fixedList = new List(4); - List fixedList2 = new List(4); + List fixedList = new List.fixedLength(4); + List fixedList2 = new List.fixedLength(4); List growableList = new List(); List growableList2 = new List(); for (int i = 0; i < 4; i++) { diff --git a/tests/language/deopt_no_feedback_test.dart b/tests/language/deopt_no_feedback_test.dart index 2d788717653..9cb79c108a5 100644 --- a/tests/language/deopt_no_feedback_test.dart +++ b/tests/language/deopt_no_feedback_test.dart @@ -14,7 +14,7 @@ testStoreIndexed() { } } - var a = new List(10); + var a = new List.fixedLength(10); for (var i = 0; i < 2000; i++) { var r = test(a, 3, 888, false); Expect.equals(3, r); diff --git a/tests/language/double_to_string_as_exponential2_test.dart b/tests/language/double_to_string_as_exponential2_test.dart new file mode 100644 index 00000000000..d9fa1a1abd4 --- /dev/null +++ b/tests/language/double_to_string_as_exponential2_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2012, 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. +// Test basic integer operations. + +main() { + // TODO(floitsch): verify that returned exception is correct type. + Expect.throws(() => (1.0).toStringAsExponential(-1), + (e) => e is RangeError); + Expect.throws(() => (1.0).toStringAsExponential(21), + (e) => e is RangeError); + Expect.throws(() => (1.0).toStringAsExponential(1.5), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => (1.0).toStringAsExponential("string"), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => (1.0).toStringAsExponential("3"), + (e) => e is ArgumentError || e is TypeError); +} diff --git a/tests/language/double_to_string_as_exponential3_test.dart b/tests/language/double_to_string_as_exponential3_test.dart new file mode 100644 index 00000000000..daaa069e4dd --- /dev/null +++ b/tests/language/double_to_string_as_exponential3_test.dart @@ -0,0 +1,11 @@ +// Copyright (c) 2012, 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. +// Test basic integer operations. + +main() { + + Expect.equals("1.00000000000000000000e+0", (1.0).toStringAsExponential(20)); + Expect.equals("1.00000000000000005551e-1", (0.1).toStringAsExponential(20)); + Expect.equals(1.00000000000000005551e-1, 0.1); +} diff --git a/tests/language/double_to_string_as_exponential_test.dart b/tests/language/double_to_string_as_exponential_test.dart index 3d9b14005e9..9827109ca3a 100644 --- a/tests/language/double_to_string_as_exponential_test.dart +++ b/tests/language/double_to_string_as_exponential_test.dart @@ -4,6 +4,9 @@ // Test basic integer operations. main() { + Expect.equals("1e+0", (1.0).toStringAsExponential()); + Expect.equals("1.1e+1", (11.0).toStringAsExponential()); + Expect.equals("1.12e+2", (112.0).toStringAsExponential()); Expect.equals("1e+0", (1.0).toStringAsExponential(null)); Expect.equals("1.1e+1", (11.0).toStringAsExponential(null)); Expect.equals("1.12e+2", (112.0).toStringAsExponential(null)); @@ -19,6 +22,9 @@ main() { Expect.equals("1.000e+0", (1.0).toStringAsExponential(3)); Expect.equals("1.100e+1", (11.0).toStringAsExponential(3)); Expect.equals("1.120e+2", (112.0).toStringAsExponential(3)); + Expect.equals("1e-1", (0.1).toStringAsExponential()); + Expect.equals("1.1e-1", (0.11).toStringAsExponential()); + Expect.equals("1.12e-1", (0.112).toStringAsExponential()); Expect.equals("1e-1", (0.1).toStringAsExponential(null)); Expect.equals("1.1e-1", (0.11).toStringAsExponential(null)); Expect.equals("1.12e-1", (0.112).toStringAsExponential(null)); @@ -35,6 +41,10 @@ main() { Expect.equals("1.100e-1", (0.11).toStringAsExponential(3)); Expect.equals("1.120e-1", (0.112).toStringAsExponential(3)); + Expect.equals("-0e+0", (-0.0).toStringAsExponential()); + Expect.equals("-1e+0", (-1.0).toStringAsExponential()); + Expect.equals("-1.1e+1", (-11.0).toStringAsExponential()); + Expect.equals("-1.12e+2", (-112.0).toStringAsExponential()); Expect.equals("-0e+0", (-0.0).toStringAsExponential(null)); Expect.equals("-1e+0", (-1.0).toStringAsExponential(null)); Expect.equals("-1.1e+1", (-11.0).toStringAsExponential(null)); @@ -51,6 +61,9 @@ main() { Expect.equals("-1.000e+0", (-1.0).toStringAsExponential(3)); Expect.equals("-1.100e+1", (-11.0).toStringAsExponential(3)); Expect.equals("-1.120e+2", (-112.0).toStringAsExponential(3)); + Expect.equals("-1e-1", (-0.1).toStringAsExponential()); + Expect.equals("-1.1e-1", (-0.11).toStringAsExponential()); + Expect.equals("-1.12e-1", (-0.112).toStringAsExponential()); Expect.equals("-1e-1", (-0.1).toStringAsExponential(null)); Expect.equals("-1.1e-1", (-0.11).toStringAsExponential(null)); Expect.equals("-1.12e-1", (-0.112).toStringAsExponential(null)); @@ -71,12 +84,15 @@ main() { Expect.equals("Infinity", (double.INFINITY).toStringAsExponential(2)); Expect.equals("-Infinity", (-double.INFINITY).toStringAsExponential(2)); Expect.equals("1e+0", (1.0).toStringAsExponential(0)); + Expect.equals("0e+0", (0.0).toStringAsExponential()); Expect.equals("0e+0", (0.0).toStringAsExponential(null)); Expect.equals("0.00e+0", (0.0).toStringAsExponential(2)); Expect.equals("1e+1", (11.2356).toStringAsExponential(0)); Expect.equals("1.1236e+1", (11.2356).toStringAsExponential(4)); Expect.equals("1.1236e-4", (0.000112356).toStringAsExponential(4)); Expect.equals("-1.1236e-4", (-0.000112356).toStringAsExponential(4)); + Expect.equals("1.12356e-4", (0.000112356).toStringAsExponential()); + Expect.equals("-1.12356e-4", (-0.000112356).toStringAsExponential()); Expect.equals("1.12356e-4", (0.000112356).toStringAsExponential(null)); Expect.equals("-1.12356e-4", (-0.000112356).toStringAsExponential(null)); } diff --git a/tests/language/double_to_string_as_fixed2_test.dart b/tests/language/double_to_string_as_fixed2_test.dart new file mode 100644 index 00000000000..f43418c6f42 --- /dev/null +++ b/tests/language/double_to_string_as_fixed2_test.dart @@ -0,0 +1,19 @@ +// Copyright (c) 2012, 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. +// Test basic integer operations. + +main() { + Expect.throws(() => 0.0.toStringAsFixed(-1), + (e) => e is RangeError); + Expect.throws(() => 0.0.toStringAsFixed(21), + (e) => e is RangeError); + Expect.throws(() => 0.0.toStringAsFixed(null), + (e) => e is ArgumentError); + Expect.throws(() => 0.0.toStringAsFixed(1.5), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.0.toStringAsFixed("string"), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.0.toStringAsFixed("3"), + (e) => e is ArgumentError || e is TypeError); +} diff --git a/tests/language/double_to_string_as_fixed_test.dart b/tests/language/double_to_string_as_fixed_test.dart index fae036365ca..80dda0cc119 100644 --- a/tests/language/double_to_string_as_fixed_test.dart +++ b/tests/language/double_to_string_as_fixed_test.dart @@ -85,24 +85,6 @@ class ToStringAsFixedTest { Expect.equals("1.3", 1.25.toStringAsFixed(1)); Expect.equals("234.2040", 234.20405.toStringAsFixed(4)); Expect.equals("234.2041", 234.2040506.toStringAsFixed(4)); - { - bool thrown = false; - try { - 0.0.toStringAsFixed(-1); - } catch (e) { - thrown = true; - } - Expect.equals(true, thrown); - } - { - bool thrown = false; - try { - 0.0.toStringAsFixed(22); - } catch (e) { - thrown = true; - } - Expect.equals(true, thrown); - } } } diff --git a/tests/language/double_to_string_as_precision2_test.dart b/tests/language/double_to_string_as_precision2_test.dart new file mode 100644 index 00000000000..ef04587b338 --- /dev/null +++ b/tests/language/double_to_string_as_precision2_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2012, 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. +// Test basic integer operations. + +main() { + Expect.throws(() => 0.0.toStringAsPrecision(0), + (e) => e is RangeError); + Expect.throws(() => 0.0.toStringAsPrecision(22), + (e) => e is RangeError); + Expect.throws(() => 0.0.toStringAsPrecision(null), + (e) => e is ArgumentError); + Expect.throws(() => 0.0.toStringAsPrecision(1.5), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.0.toStringAsPrecision("string"), + (e) => e is ArgumentError || e is TypeError); + Expect.throws(() => 0.0.toStringAsPrecision("3"), + (e) => e is ArgumentError || e is TypeError); + +} diff --git a/tests/language/double_to_string_as_precision3_test.dart b/tests/language/double_to_string_as_precision3_test.dart new file mode 100644 index 00000000000..b2d4e32370f --- /dev/null +++ b/tests/language/double_to_string_as_precision3_test.dart @@ -0,0 +1,16 @@ +// Copyright (c) 2012, 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. +// Test basic integer operations. + +main() { + Expect.equals("0.000555000000000000046248", + (0.000555).toStringAsPrecision(21)); + Expect.equals(0.000555000000000000046248, 0.000555); + Expect.equals("5.54999999999999980179e-7", + (0.000000555).toStringAsPrecision(21)); + Expect.equals(5.54999999999999980179e-7, 0.000000555); + Expect.equals("-5.54999999999999980179e-7", + (-0.000000555).toStringAsPrecision(21)); + Expect.equals(-5.54999999999999980179e-7, -0.000000555); +} diff --git a/tests/language/execute_finally7_test.dart b/tests/language/execute_finally7_test.dart index 265e4c17cfa..6b68a0b0277 100644 --- a/tests/language/execute_finally7_test.dart +++ b/tests/language/execute_finally7_test.dart @@ -14,7 +14,7 @@ class Helper { static int f1(int k) { var b; try { - var a = new List(10); + var a = new List.fixedLength(10); int i = 0; while (i < 10) { int j = i; diff --git a/tests/language/fannkuch_test.dart b/tests/language/fannkuch_test.dart index 356f20f588f..a38d34dde07 100644 --- a/tests/language/fannkuch_test.dart +++ b/tests/language/fannkuch_test.dart @@ -8,7 +8,7 @@ class FannkuchTest { static fannkuch(n) { - var p = new List(n), q = new List(n), s = new List(n); + var p = new List.fixedLength(n), q = new List.fixedLength(n), s = new List.fixedLength(n); var sign = 1, maxflips = 0, sum = 0, m = n - 1; for (var i = 0; i < n; i++) { p[i] = i; q[i] = i; s[i] = i; } do { diff --git a/tests/language/gc_test.dart b/tests/language/gc_test.dart index b64a4e31ea9..9ae29a27965 100644 --- a/tests/language/gc_test.dart +++ b/tests/language/gc_test.dart @@ -7,12 +7,12 @@ main() { var div; for (int i = 0; i < 200; ++i) { - List l = new List(1000000); + List l = new List.fixedLength(1000000); var m = 2; div = (_) { var b = l; // Was causing OutOfMemory. }; - var lSmall = new List(3); + var lSmall = new List.fixedLength(3); // Circular reference between new and old gen objects. lSmall[0] = l; l[0] = lSmall; diff --git a/tests/language/generic_instanceof.dart b/tests/language/generic_instanceof.dart index 3f64976d6b5..5c65ec12fdd 100644 --- a/tests/language/generic_instanceof.dart +++ b/tests/language/generic_instanceof.dart @@ -37,91 +37,91 @@ class GenericInstanceof { } { Foo foo = new Foo(); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); } { Foo foo = new Foo(); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); } { Foo foo = new Foo>(); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); } { Foo foo = new Foo>(); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); } { Foo foo = new Foo>(); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); } { Foo foo = new Foo>(); - Expect.equals(true, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); - Expect.equals(false, foo.isT(new List(5))); - Expect.equals(true, foo.isT(new List(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); + Expect.equals(false, foo.isT(new List.fixedLength(5))); + Expect.equals(true, foo.isT(new List.fixedLength(5))); } { Foo foo = new Foo(); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); } { Foo foo = new Foo(); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); } { Foo foo = new Foo(); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); } { Foo foo = new Foo(); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); } { Foo foo = new Foo(); - Expect.equals(true, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); - Expect.equals(false, foo.isListT(new List(5))); - Expect.equals(true, foo.isListT(new List(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); + Expect.equals(false, foo.isListT(new List.fixedLength(5))); + Expect.equals(true, foo.isListT(new List.fixedLength(5))); } } } diff --git a/tests/language/incr_op_test.dart b/tests/language/incr_op_test.dart index be772e7829c..32730bde3c8 100644 --- a/tests/language/incr_op_test.dart +++ b/tests/language/incr_op_test.dart @@ -60,7 +60,7 @@ class IncrOpTest { Expect.equals(57, IncrOpTest.y); Expect.equals(56, --IncrOpTest.y); - var list = new List(4); + var list = new List.fixedLength(4); for (int i = 0; i < list.length; i++) { list[i] = i; } diff --git a/tests/language/index_test.dart b/tests/language/index_test.dart index 9e1c634621a..3462e4e8e33 100644 --- a/tests/language/index_test.dart +++ b/tests/language/index_test.dart @@ -18,7 +18,7 @@ class IndexTest { static const ID_IDLE = 0; static testMain() { - var a = new List(10); + var a = new List.fixedLength(10); Expect.equals(10, a.length); for (int i = 0; i < a.length; i++) { a[i] = Helper.fibonacci(i); diff --git a/tests/language/inst_field_initializer1_negative_test.dart b/tests/language/inst_field_initializer1_negative_test.dart index 44fcca13a11..1c56eb0fa8f 100644 --- a/tests/language/inst_field_initializer1_negative_test.dart +++ b/tests/language/inst_field_initializer1_negative_test.dart @@ -7,7 +7,7 @@ class A { A() {} int x = 5; - int arr = new List(x); // Illegal access to 'this'. + int arr = new List.fixedLength(x); // Illegal access to 'this'. // Also not a compile const expression. } diff --git a/tests/language/instanceof2_test.dart b/tests/language/instanceof2_test.dart index f93c0b39002..0655b866397 100644 --- a/tests/language/instanceof2_test.dart +++ b/tests/language/instanceof2_test.dart @@ -54,7 +54,7 @@ class InstanceofTest { Expect.equals(false, null is I); { - var a = new List(5); + var a = new List.fixedLength(5); Expect.equals(true, a is List); Expect.equals(true, a is List); Expect.equals(true, a is List); @@ -62,7 +62,7 @@ class InstanceofTest { Expect.equals(true, a is List); } { - var a = new List(5); + var a = new List.fixedLength(5); Expect.equals(true, a is List); Expect.equals(true, a is List); Expect.equals(false, a is List); @@ -70,7 +70,7 @@ class InstanceofTest { Expect.equals(false, a is List); } { - var a = new List(5); + var a = new List.fixedLength(5); Expect.equals(true, a is List); Expect.equals(true, a is List); Expect.equals(true, a is List); @@ -78,7 +78,7 @@ class InstanceofTest { Expect.equals(false, a is List); } { - var a = new List(5); + var a = new List.fixedLength(5); Expect.equals(true, a is List); Expect.equals(true, a is List); Expect.equals(false, a is List); @@ -86,7 +86,7 @@ class InstanceofTest { Expect.equals(false, a is List); } { - var a = new List(5); + var a = new List.fixedLength(5); Expect.equals(true, a is List); Expect.equals(true, a is List); Expect.equals(false, a is List); diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status index d9bdf96fe98..238e96ca43b 100644 --- a/tests/language/language_dart2js.status +++ b/tests/language/language_dart2js.status @@ -70,6 +70,10 @@ factory_redirection_test/12: Fail factory_redirection_test/13: Fail factory_redirection_test/14: Fail +double_to_string_as_exponential2_test: Fail # toStringAsExponential doesn't check if argument is an integer. +double_to_string_as_fixed2_test: Fail # toStringAsFixed doesn't check if argument is an integer. +double_to_string_as_precision2_test: Fail # toStringAsPrecision doesn't check if argument is an integer. + # Only checked mode reports an error on type assignment # problems in compile time constants. compile_time_constant_checked_test/02: Fail, OK diff --git a/tests/language/list_test.dart b/tests/language/list_test.dart index 8ab8870a67c..a94b14b5d53 100644 --- a/tests/language/list_test.dart +++ b/tests/language/list_test.dart @@ -5,7 +5,7 @@ class ListTest { static void TestIterator() { - List a = new List(10); + List a = new List.fixedLength(10); int count = 0; // Basic iteration over ObjectList. @@ -42,7 +42,7 @@ class ListTest { static void testMain() { int len = 10; - List a = new List(len); + List a = new List.fixedLength(len); Expect.equals(true, a is List); Expect.equals(len, a.length); a.forEach((element) { Expect.equals(null, element); }); @@ -51,17 +51,17 @@ class ListTest { Expect.throws(() => a[len], (e) => e is RangeError); Expect.throws(() { - List a = new List(4); + List a = new List.fixedLength(4); a.setRange(1, 1, a, null); - }, (e) => true); + }); Expect.throws(() { - List a = new List(4); + List a = new List.fixedLength(4); a.setRange(10, 1, a, 1); }, (e) => e is RangeError); - a = new List(4); - List b = new List(4); + a = new List.fixedLength(4); + List b = new List.fixedLength(4); b.setRange(0, 4, a, 0); List unsorted = [4, 3, 9, 12, -4, 9]; @@ -95,8 +95,8 @@ class ListTest { Expect.throws(() => unsorted[2.1], (e) => e is ArgumentError || e is TypeError); - Expect.throws(() => new List(-1), (e) => true); - Expect.throws(() => new List(99999999999999999999999), (e) => true); + Expect.throws(() => new List.fixedLength(-1)); + Expect.throws(() => new List.fixedLength(99999999999999999999999)); List list = new List(); // We cannot write just 'list.removeLast' due to issue 3769. diff --git a/tests/language/local_function_test.dart b/tests/language/local_function_test.dart index 104319ff68b..82f5fc2fbc7 100644 --- a/tests/language/local_function_test.dart +++ b/tests/language/local_function_test.dart @@ -16,8 +16,8 @@ class LocalFunctionTest { } static int h(int n) { k(int n) { - var a = new List(n); - var b = new List(n); + var a = new List.fixedLength(n); + var b = new List.fixedLength(n); int i; for (i = 0; i < n; i++) { var j = i; @@ -36,8 +36,8 @@ class LocalFunctionTest { } static int h2(int n) { k(int n) { - var a = new List(n); - var b = new List(n); + var a = new List.fixedLength(n); + var b = new List.fixedLength(n); for (int i = 0; i < n; i++) { var j = i; a[i] = () => i; // Captured i varies from 0 to n-1. @@ -94,7 +94,7 @@ class LocalFunctionTest { f(); } static testNesting(int n) { - var a = new List(n*n); + var a = new List.fixedLength(n*n); f0() { for (int i = 0; i < n; i++) { int vi = i; diff --git a/tests/language/many_calls_test.dart b/tests/language/many_calls_test.dart index c59b90ff54f..a8db4766155 100644 --- a/tests/language/many_calls_test.dart +++ b/tests/language/many_calls_test.dart @@ -53,7 +53,7 @@ class B extends A { class ManyCallsTest { static testMain() { - var list = new List(10); + var list = new List.fixedLength(10); for (int i = 0; i < (list.length ~/ 2) ; i++) { list[i] = new A(); } diff --git a/tests/language/map_test.dart b/tests/language/map_test.dart index 3968cf8a0ef..a055f769652 100644 --- a/tests/language/map_test.dart +++ b/tests/language/map_test.dart @@ -158,7 +158,7 @@ class MapTest { void testForEachCollection(value) { other_map[value] = value; } - Collection keys = map.keys; + Iterable keys = map.keys; keys.forEach(testForEachCollection); Expect.equals(true, other_map.containsKey(key1)); Expect.equals(true, other_map.containsKey(key2)); @@ -173,7 +173,7 @@ class MapTest { Expect.equals(0, other_map.length); // Test Collection.values. - Collection values = map.values; + Iterable values = map.values; values.forEach(testForEachCollection); Expect.equals(true, !other_map.containsKey(key1)); Expect.equals(true, !other_map.containsKey(key2)); @@ -200,9 +200,9 @@ class MapTest { static testKeys(Map map) { map[1] = 101; map[2] = 102; - Collection k = map.keys; + Iterable k = map.keys; Expect.equals(2, k.length); - Collection v = map.values; + Iterable v = map.values; Expect.equals(2, v.length); Expect.equals(true, map.containsValue(101)); Expect.equals(true, map.containsValue(102)); diff --git a/tests/language/math_vm_test.dart b/tests/language/math_vm_test.dart index 3d1325d707f..cde27ef770c 100644 --- a/tests/language/math_vm_test.dart +++ b/tests/language/math_vm_test.dart @@ -16,7 +16,7 @@ class FakeNumber { class MathTest { static bool testParseInt(x) { try { - parseInt(x); // Expects string. + int.parse(x); // Expects string. return true; } catch (e) { return false; diff --git a/tests/language/optimization_test.dart b/tests/language/optimization_test.dart index 3d1eb49b834..be41f4f7bb6 100644 --- a/tests/language/optimization_test.dart +++ b/tests/language/optimization_test.dart @@ -79,7 +79,7 @@ main() { // Deoptimize. Expect.equals(-5, doNeg2(5)); - var fixed = new List(10); + var fixed = new List.fixedLength(10); var growable = [1, 2, 3, 4, 5]; for (int i = 0; i < 2000; i++) { diff --git a/tests/language/optimized_lists_test.dart b/tests/language/optimized_lists_test.dart index cc3b86299a3..cd2a59648c0 100644 --- a/tests/language/optimized_lists_test.dart +++ b/tests/language/optimized_lists_test.dart @@ -13,7 +13,7 @@ main() { test(n) { var a = new List(); // Growable list. - var b = new List(10); // Fixed size list. + var b = new List.fixedLength(10); // Fixed size list. var c = const [1, 2, 3, 4]; // Constant aray. // In optimized mode the class checks will be eliminated since the // constructors above provide information about exact types. diff --git a/tests/language/ordered_maps_test.dart b/tests/language/ordered_maps_test.dart index ef0e8d923f1..e375877e85b 100644 --- a/tests/language/ordered_maps_test.dart +++ b/tests/language/ordered_maps_test.dart @@ -13,22 +13,22 @@ class OrderedMapsTest { static void testMaps(map1, map2, bool isConst) { Expect.isFalse(identical(map1, map2)); - var keys = map1.keys; + var keys = map1.keys.toList(); Expect.equals(2, keys.length); Expect.equals("a", keys[0]); Expect.equals("c", keys[1]); - keys = map2.keys; + keys = map2.keys.toList(); Expect.equals(2, keys.length); Expect.equals("c", keys[0]); Expect.equals("a", keys[1]); - var values = map1.values; + var values = map1.values.toList(); Expect.equals(2, values.length); Expect.equals(1, values[0]); Expect.equals(2, values[1]); - values = map2.values; + values = map2.values.toList(); Expect.equals(2, values.length); Expect.equals(2, values[0]); Expect.equals(1, values[1]); @@ -38,36 +38,36 @@ class OrderedMapsTest { map1["b"] = 3; map2["b"] = 3; - keys = map1.keys; + keys = map1.keys.toList(); Expect.equals(3, keys.length); Expect.equals("a", keys[0]); Expect.equals("c", keys[1]); Expect.equals("b", keys[2]); - keys = map2.keys; + keys = map2.keys.toList(); Expect.equals(3, keys.length); Expect.equals("c", keys[0]); Expect.equals("a", keys[1]); Expect.equals("b", keys[2]); - values = map1.values; + values = map1.values.toList(); Expect.equals(3, values.length); Expect.equals(1, values[0]); Expect.equals(2, values[1]); Expect.equals(3, values[2]); - values = map2.values; + values = map2.values.toList(); Expect.equals(3, values.length); Expect.equals(2, values[0]); Expect.equals(1, values[1]); Expect.equals(3, values[2]); map1["a"] = 4; - keys = map1.keys; + keys = map1.keys.toList(); Expect.equals(3, keys.length); Expect.equals("a", keys[0]); - values = map1.values; + values = map1.values.toList(); Expect.equals(3, values.length); Expect.equals(4, values[0]); } diff --git a/tests/language/string_test.dart b/tests/language/string_test.dart index f2072ff8a0e..9e843966a44 100644 --- a/tests/language/string_test.dart +++ b/tests/language/string_test.dart @@ -21,7 +21,7 @@ class StringTest { } static testStringsJoin() { - List a = new List(2); + List a = new List.fixedLength(2); a[0] = "Hello"; a[1] = "World"; String s = Strings.join(a, "*^*"); diff --git a/tests/language/type_cast_vm_test.dart b/tests/language/type_cast_vm_test.dart index 22e34375cfd..fdf4cc9e7ef 100644 --- a/tests/language/type_cast_vm_test.dart +++ b/tests/language/type_cast_vm_test.dart @@ -38,7 +38,7 @@ class TypeTest { return 0; } try { - var a = new List(1) as List; + var a = new List.fixedLength(1) as List; a[0] = 0; a[index()]++; // Type check succeeds, but does not create side effects. Expect.equals(1, a[0]); diff --git a/tests/language/type_vm_test.dart b/tests/language/type_vm_test.dart index 7b525a13a66..1b82769b21b 100644 --- a/tests/language/type_vm_test.dart +++ b/tests/language/type_vm_test.dart @@ -34,7 +34,7 @@ class TypeTest { return 0; } try { - List a = new List(1); + List a = new List.fixedLength(1); a[0] = 0; a[index()]++; // Type check succeeds, but does not create side effects. Expect.equals(1, a[0]); @@ -377,7 +377,7 @@ class TypeTest { static int testListAssigment() { int result = 0; { - var a = new List(5); + var a = new List.fixedLength(5); List a0 = a; List ao = a; List ai = a; @@ -385,7 +385,7 @@ class TypeTest { List as = a; } { - var a = new List(5); + var a = new List.fixedLength(5); List a0 = a; List ao = a; try { @@ -438,7 +438,7 @@ class TypeTest { } } { - var a = new List(5); + var a = new List.fixedLength(5); List a0 = a; List ao = a; List ai = a; @@ -461,7 +461,7 @@ class TypeTest { } } { - var a = new List(5); + var a = new List.fixedLength(5); List a0 = a; List ao = a; try { @@ -499,7 +499,7 @@ class TypeTest { } } { - var a = new List(5); + var a = new List.fixedLength(5); List a0 = a; List ao = a; try { diff --git a/tests/language/typed_message_test.dart b/tests/language/typed_message_test.dart index 4c23387972d..bda98146d20 100644 --- a/tests/language/typed_message_test.dart +++ b/tests/language/typed_message_test.dart @@ -26,7 +26,7 @@ void logMessages() { main() { SendPort remote = spawnFunction(logMessages); - List msg = new List(5); + List msg = new List.fixedLength(5); for (int i = 0; i < 5; i++) { msg[i] = i; } diff --git a/tests/lib/async/event_helper.dart b/tests/lib/async/event_helper.dart new file mode 100644 index 00000000000..409e0c85933 --- /dev/null +++ b/tests/lib/async/event_helper.dart @@ -0,0 +1,173 @@ +// Copyright (c) 2012, 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. + +library event_helper; + +import 'dart:async'; + +class Event { + void replay(StreamSink sink); +} + +class DataEvent implements Event { + final data; + + DataEvent(this.data); + + void replay(StreamSink sink) { sink.add(data); } + + int get hashCode => data.hashCode; + + bool operator==(Object other) { + if (other is! DataEvent) return false; + DataEvent otherEvent = other; + return data == other.data; + } + + String toString() => "DataEvent: $data"; +} + +class ErrorEvent implements Event { + final AsyncError error; + + ErrorEvent(this.error); + + void replay(StreamSink sink) { sink.signalError(error); } + + int get hashCode => error.error.hashCode; + + bool operator==(Object other) { + if (other is! ErrorEvent) return false; + ErrorEvent otherEvent = other; + return error.error == other.error.error; + } + + String toString() => "ErrorEvent: ${error.error}"; +} + +class DoneEvent implements Event { + const DoneEvent(); + + void replay(StreamSink sink) { sink.close(); } + + int get hashCode => 42; + + bool operator==(Object other) => other is DoneEvent; + + String toString() => "DoneEvent"; +} + +/** Collector of events. */ +class Events implements StreamSink { + final List events = []; + + Events(); + Events.fromIterable(Iterable iterable) { + for (var value in iterable) add(value); + close(); + } + + /** Capture events from a stream into a new [Events] object. */ + factory Events.capture(Stream stream, + { bool unsubscribeOnError: false }) = CaptureEvents; + + // Sink interface. + add(var value) { events.add(new DataEvent(value)); } + + void signalError(AsyncError error) { + events.add(new ErrorEvent(error)); + } + + void close() { + events.add(const DoneEvent()); + } + + // Error helper for creating errors manually.. + void error(var value) { signalError(new AsyncError(value, null)); } + + /** Replay the captured events on a sink. */ + void replay(StreamSink sink) { + for (int i = 0; i < events.length; i++) { + events[i].replay(sink); + } + } + + /** + * Create a new [Events] with the same captured events. + * + * This does not copy a subscription. + */ + Events copy() { + Events result = new Events(); + replay(result); + return result; + } + + // Operations that only work when there is a subscription feeding the Events. + + /** + * Pauses the subscription that feeds this [Events]. + * + * Should only be used when there is a subscription. That is, after a + * call to [subscribeTo]. + */ + void pause([Signal resumeSignal]) { + throw new StateError("Not capturing events."); + } + + /** Resumes after a call to [pause]. */ + void resume() { + throw new StateError("Not capturing events."); + } + + /** Whether the underlying subscription has been paused. */ + bool get isPaused => false; + + /** + * Sets an action to be called when this [Events] receives a 'done' event. + */ + void onDone(void action()) { + throw new StateError("Not capturing events."); + } +} + +class CaptureEvents extends Events { + StreamSubscription subscription; + SignalCompleter onDoneSignal; + bool unsubscribeOnError = false; + + CaptureEvents(Stream stream, + { bool unsubscribeOnError: false }) + : onDoneSignal = new SignalCompleter() { + this.unsubscribeOnError = unsubscribeOnError; + subscription = stream.listen(add, + onError: signalError, + onDone: close, + unsubscribeOnError: unsubscribeOnError); + } + + void signalError(AsyncError error) { + super.signalError(error); + if (unsubscribeOnError) onDoneSignal.complete(); + } + + void close() { + super.close(); + if (onDoneSignal != null) onDoneSignal.complete(); + } + + void pause([Signal resumeSignal]) { + subscription.pause(resumeSignal); + } + + void resume() { + subscription.resume(); + } + + bool get isPaused => subscription.isPaused; + + void onDone(void action()) { + onDoneSignal.signal.then(action); + } +} diff --git a/tests/lib/async/future_delayed_error_test.dart b/tests/lib/async/future_delayed_error_test.dart new file mode 100644 index 00000000000..a3fea32a569 --- /dev/null +++ b/tests/lib/async/future_delayed_error_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2012, 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. + +import 'dart:async'; +import 'dart:isolate'; + +testImmediateError() { + // An open ReceivePort keeps the VM running. If the error-handler below is not + // executed then the test will fail with a timeout. + var port = new ReceivePort(); + var future = new Future.immediateError("error"); + future.catchError((e) { + port.close(); + Expect.equals(e.error, "error"); + }); +} + +Future get completedFuture { + var completer = new Completer(); + completer.completeError("foobar"); + return completer.future; +} + +testDelayedError() { + var port = new ReceivePort(); + completedFuture.catchError((e) { + port.close(); + Expect.equals(e.error, "foobar"); + }); +} + +main() { + testImmediateError(); + testDelayedError(); +} + diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart new file mode 100644 index 00000000000..0826db3af0d --- /dev/null +++ b/tests/lib/async/future_test.dart @@ -0,0 +1,196 @@ +// Copyright (c) 2012, 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. + +import 'dart:async'; +import 'dart:isolate'; + +testFutureAsStreamCompleteAfter() { + var completer = new Completer(); + bool gotValue = false; + var port = new ReceivePort(); + completer.future.asStream().listen( + (data) { + Expect.isFalse(gotValue); + gotValue = true; + Expect.equals("value", data); + }, + onDone: () { + Expect.isTrue(gotValue); + port.close(); + }); + completer.complete("value"); +} + +testFutureAsStreamCompleteBefore() { + var completer = new Completer(); + bool gotValue = false; + var port = new ReceivePort(); + completer.complete("value"); + completer.future.asStream().listen( + (data) { + Expect.isFalse(gotValue); + gotValue = true; + Expect.equals("value", data); + }, + onDone: () { + Expect.isTrue(gotValue); + port.close(); + }); +} + +testFutureAsStreamCompleteImmediate() { + bool gotValue = false; + var port = new ReceivePort(); + new Future.immediate("value").asStream().listen( + (data) { + Expect.isFalse(gotValue); + gotValue = true; + Expect.equals("value", data); + }, + onDone: () { + Expect.isTrue(gotValue); + port.close(); + }); +} + +testFutureAsStreamCompleteErrorAfter() { + var completer = new Completer(); + bool gotError = false; + var port = new ReceivePort(); + completer.future.asStream().listen( + (data) { + Expect.fail("Unexpected data"); + }, + onError: (error) { + Expect.isFalse(gotError); + gotError = true; + Expect.equals("error", error.error); + }, + onDone: () { + Expect.isTrue(gotError); + port.close(); + }); + completer.completeError("error"); +} + +testFutureAsStreamWrapper() { + var completer = new Completer(); + bool gotValue = false; + var port = new ReceivePort(); + completer.complete("value"); + completer.future + .catchError((_) { throw "not possible"; }) // Returns a future wrapper. + .asStream().listen( + (data) { + Expect.isFalse(gotValue); + gotValue = true; + Expect.equals("value", data); + }, + onDone: () { + Expect.isTrue(gotValue); + port.close(); + }); +} + +testFutureWhenCompleteValue() { + var port = new ReceivePort(); + int counter = 2; + countDown() { + if (--counter == 0) port.close(); + } + var completer = new Completer(); + Future future = completer.future; + Future later = future.whenComplete(countDown); + later.then((v) { + Expect.equals(42, v); + countDown(); + }); + completer.complete(42); +} + +testFutureWhenCompleteError() { + var port = new ReceivePort(); + int counter = 2; + countDown() { + if (--counter == 0) port.close(); + } + var completer = new Completer(); + Future future = completer.future; + Future later = future.whenComplete(countDown); + later.catchError((AsyncError e) { + Expect.equals("error", e.error); + countDown(); + }); + completer.completeError("error"); +} + +testFutureWhenCompleteValueNewError() { + var port = new ReceivePort(); + int counter = 2; + countDown() { + if (--counter == 0) port.close(); + } + var completer = new Completer(); + Future future = completer.future; + Future later = future.whenComplete(() { + countDown(); + throw "new error"; + }); + later.catchError((AsyncError e) { + Expect.equals("new error", e.error); + countDown(); + }); + completer.complete(42); +} + +testFutureWhenCompleteErrorNewError() { + var port = new ReceivePort(); + int counter = 2; + countDown() { + if (--counter == 0) port.close(); + } + var completer = new Completer(); + Future future = completer.future; + Future later = future.whenComplete(() { + countDown(); + throw "new error"; + }); + later.catchError((AsyncError e) { + Expect.equals("new error", e.error); + countDown(); + }); + completer.completeError("error"); +} + +testFutureWhenCompletePreValue() { + var port = new ReceivePort(); + int counter = 2; + countDown() { + if (--counter == 0) port.close(); + } + var completer = new Completer(); + Future future = completer.future; + completer.complete(42); + new Timer(0, () { + Future later = future.whenComplete(countDown); + later.then((v) { + Expect.equals(42, v); + countDown(); + }); + }); +} + +main() { + testFutureAsStreamCompleteAfter(); + testFutureAsStreamCompleteBefore(); + testFutureAsStreamCompleteImmediate(); + testFutureAsStreamCompleteErrorAfter(); + testFutureAsStreamWrapper(); + + testFutureWhenCompleteValue(); + testFutureWhenCompleteError(); + testFutureWhenCompleteValueNewError(); + testFutureWhenCompleteErrorNewError(); +} + diff --git a/tests/lib/async/merge_stream_test.dart b/tests/lib/async/merge_stream_test.dart new file mode 100644 index 00000000000..1d47cf0ae80 --- /dev/null +++ b/tests/lib/async/merge_stream_test.dart @@ -0,0 +1,172 @@ +// 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. + +// Test merging streams. +import "dart:async"; +import '../../../pkg/unittest/lib/unittest.dart'; +import 'event_helper.dart'; + +testSupercedeStream() { + { // Simple case of superceding lower priority streams. + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.superceding([s1.stream, s2.stream, s3.stream]); + Events expected = new Events()..add(1)..add(2)..add(3)..add(4)..close(); + Events actual = new Events.capture(merge); + s1.add(1); + s2.add(2); + s1.add(1); // Ignored. + s2.add(3); + s3.add(4); + s2.add(3); // Ignored. + s3.close(); + Expect.listEquals(expected.events, actual.events); + } + + { // Superceding more than one stream at a time. + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.superceding([s1.stream, s2.stream, s3.stream]); + Events expected = new Events()..add(1)..add(2)..close(); + Events actual = new Events.capture(merge); + s1.add(1); + s3.add(2); + s1.add(1); // Ignored. + s2.add(1); // Ignored. + s3.close(); + Expect.listEquals(expected.events, actual.events); + } + + { // Closing a stream before superceding it. + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.superceding([s1.stream, s2.stream, s3.stream]); + Events expected = new Events()..add(1)..add(2)..add(3)..close(); + Events actual = new Events.capture(merge); + s1.add(1); + s1.close(); + s3.close(); + s2.add(2); + s2.add(3); + s2.close(); + Expect.listEquals(expected.events, actual.events); + } + + { // Errors from all non-superceded streams are forwarded. + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.superceding([s1.stream, s2.stream, s3.stream]); + Events expected = + new Events()..add(1)..error("1")..error("2")..error("3") + ..add(3)..error("6")..add(4)..close(); + Events actual = new Events.capture(merge); + s1.add(1); + s1.signalError(new AsyncError("1")); + s2.signalError(new AsyncError("2")); + s3.signalError(new AsyncError("3")); + s3.add(3); + s1.signalError(new AsyncError("4")); + s2.signalError(new AsyncError("5")); + s3.signalError(new AsyncError("6")); + s1.close(); + s2.close(); + s3.add(4); + s3.close(); + Expect.listEquals(expected.events, actual.events); + } + + test("Pausing on a superceding stream", () { + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.superceding([s1.stream, s2.stream, s3.stream]); + Events expected = new Events()..add(1)..add(2)..add(3); + Events actual = new Events.capture(merge); + s1.add(1); + s2.add(2); + s2.add(3); + Expect.listEquals(expected.events, actual.events); + actual.pause(); // Pauses the stream that feeds the actual Events. + Events expected2 = expected.copy(); + expected..add(5)..add(6)..close(); + expected2..add(6)..close(); + s1.add(4); + s2.add(5); // May or may not arrive before '6' when resuming. + s3.add(6); + s3.close(); + actual.onDone(expectAsync0(() { + if (expected.events.length == actual.events.length) { + Expect.listEquals(expected.events, actual.events); + } else { + Expect.listEquals(expected2.events, actual.events); + } + })); + actual.resume(); + }); +} + +void testCyclicStream() { + test("Simple case of superceding lower priority streams", () { + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.cyclic([s1.stream, s2.stream, s3.stream]); + Events expected = + new Events()..add(1)..add(2)..add(3)..add(4)..add(5)..add(6)..close(); + Events actual = new Events.capture(merge); + Expect.isFalse(s1.isPaused); + Expect.isTrue(s2.isPaused); + Expect.isTrue(s3.isPaused); + s3.add(3); + s1.add(1); + s1.add(4); + s1.add(6); + s1.close(); + s2.add(2); + s2.add(5); + s2.close(); + s3.close(); + actual.onDone(expectAsync0(() { + Expect.listEquals(expected.events, actual.events); + })); + }); + + test("Cyclic merge with errors", () { + StreamController s1 = new StreamController(); + StreamController s2 = new StreamController(); + StreamController s3 = new StreamController(); + Stream merge = new Stream.cyclic([s1.stream, s2.stream, s3.stream]); + Events expected = + new Events()..add(1)..error("1")..add(2)..add(3)..error("2") + ..add(4)..add(5)..error("3")..add(6)..close(); + Events actual = new Events.capture(merge); + Expect.isFalse(s1.isPaused); + Expect.isTrue(s2.isPaused); + Expect.isTrue(s3.isPaused); + s3.add(3); + s3.signalError(new AsyncError("3")); // Error just before a "done". + s1.add(1); + s1.signalError(new AsyncError("2")); // Error between events. + s1.add(4); + s1.add(6); + s1.close(); + s2.signalError(new AsyncError("1")); // Error as first event. + s2.add(2); + s2.add(5); + s2.close(); + s3.close(); + actual.onDone(expectAsync0(() { + Expect.listEquals(expected.events, actual.events); + })); + }); +} + +main() { + testSupercedeStream(); + testCyclicStream(); +} diff --git a/tests/lib/async/slow_consumer2_test.dart b/tests/lib/async/slow_consumer2_test.dart new file mode 100644 index 00000000000..68f5b3c53d5 --- /dev/null +++ b/tests/lib/async/slow_consumer2_test.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2012, 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. + +// VMOptions=--old_gen_heap_size=32 + +import 'dart:async'; +import 'dart:isolate'; + +const int KB = 1024; +const int MB = KB * KB; +const int GB = KB * KB * KB; + +class SlowConsumer extends StreamConsumer { + int receivedCount = 0; + final int bytesPerSecond; + final int bufferSize; + final List bufferedData = []; + int usedBufferSize = 0; + + SlowConsumer(int this.bytesPerSecond, int this.bufferSize); + + Future consume(Stream stream) { + Completer result = new Completer(); + var subscription; + subscription = stream.listen( + (List data) { + receivedCount += data.length; + usedBufferSize += data.length; + bufferedData.add(data); + int currentBufferedDataLength = bufferedData.length; + if (usedBufferSize > bufferSize) { + subscription.pause(); + usedBufferSize = 0; + int ms = data.length * 1000 ~/ bytesPerSecond; + new Timer(ms, (_) { + for (int i = 0; i < currentBufferedDataLength; i++) { + bufferedData[i] = null; + } + subscription.resume(); + }); + } + }, + onDone: () { result.complete(receivedCount); }); + return result.future; + } +} + +class DataProvider extends StreamController { + final int chunkSize; + final int bytesPerSecond; + int sentCount = 0; + int targetCount; + + DataProvider(int this.bytesPerSecond, int this.targetCount, this.chunkSize) { + new Timer(0, (_) => send()); + } + + send() { + if (isPaused) return; + if (sentCount == targetCount) { + close(); + return; + } + int listSize = chunkSize; + sentCount += listSize; + if (sentCount > targetCount) { + listSize -= sentCount - targetCount; + sentCount = targetCount; + } + add(new List.fixedLength(listSize)); + int ms = listSize * 1000 ~/ bytesPerSecond; + if (!isPaused) new Timer(ms, (_) => send()); + } + + onPauseStateChange() { + // We don't care if we just unpaused or paused. In either case we just + // call send which will test it for us. + send(); + } +} + +main() { + var port = new ReceivePort(); + // The data provider can deliver 800MB/s of data. It sends 100MB of data to + // the slower consumer who can only read 200MB/s. The data is sent in 1MB + // chunks. The consumer has a buffer of 5MB. That is, it can accept a few + // packages without pausing its input. + // + // This test is limited to 32MB of heap-space (see VMOptions on top of the + // file). If the consumer doesn't pause the data-provider it will run out of + // heap-space. + + new DataProvider(800 * MB, 100 * MB, 1 * MB) + .pipe(new SlowConsumer(200 * MB, 5 * MB)) + .then((count) { + port.close(); + Expect.equals(100 * MB, count); + }); +} diff --git a/tests/lib/async/slow_consumer_test.dart b/tests/lib/async/slow_consumer_test.dart new file mode 100644 index 00000000000..e99ab5bd4ca --- /dev/null +++ b/tests/lib/async/slow_consumer_test.dart @@ -0,0 +1,92 @@ +// Copyright (c) 2012, 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. + +// VMOptions=--old_gen_heap_size=32 + +import 'dart:async'; +import 'dart:isolate'; + +const int KB = 1024; +const int MB = KB * KB; +const int GB = KB * KB * KB; + +class SlowConsumer extends StreamConsumer { + var current = new Future.immediate(0); + final int bytesPerSecond; + + SlowConsumer(int this.bytesPerSecond); + + Future consume(Stream stream) { + Completer completer = new Completer(); + var subscription; + subscription = stream.listen( + (List data) { + current = current + .then((count) { + // Simulated amount of time it takes to handle the data. + int ms = data.length * 1000 ~/ bytesPerSecond; + subscription.pause(); + return new Future.delayed(ms, () { + subscription.resume(); + // Make sure we use data here to keep tracking it. + return count + data.length; + }); + }); + }, + onDone: () { current.then((count) { completer.complete(count); }); }); + return completer.future; + } +} + +class DataProvider extends StreamController { + final int chunkSize; + final int bytesPerSecond; + int sentCount = 0; + int targetCount; + + DataProvider(int this.bytesPerSecond, int this.targetCount, this.chunkSize) { + new Timer(0, (_) => send()); + } + + send() { + if (isPaused) return; + if (sentCount == targetCount) { + close(); + return; + } + int listSize = chunkSize; + sentCount += listSize; + if (sentCount > targetCount) { + listSize -= sentCount - targetCount; + sentCount = targetCount; + } + add(new List.fixedLength(listSize)); + int ms = listSize * 1000 ~/ bytesPerSecond; + if (!isPaused) new Timer(ms, (_) => send()); + } + + onPauseStateChange() { + // We don't care if we just unpaused or paused. In either case we just + // call send which will test it for us. + send(); + } +} + +main() { + var port = new ReceivePort(); + // The data provider can deliver 800MB/s of data. It sends 100MB of data to + // the slower consumer who can only read 200MB/s. The data is sent in 1MB + // chunks. + // + // This test is limited to 32MB of heap-space (see VMOptions on top of the + // file). If the consumer doesn't pause the data-provider it will run out of + // heap-space. + + new DataProvider(800 * MB, 100 * MB, 1 * MB) + .pipe(new SlowConsumer(200 * MB)) + .then((count) { + port.close(); + Expect.equals(100 * MB, count); + }); +} diff --git a/tests/lib/async/stream_controller_async_test.dart b/tests/lib/async/stream_controller_async_test.dart new file mode 100644 index 00000000000..3c65a7e87f9 --- /dev/null +++ b/tests/lib/async/stream_controller_async_test.dart @@ -0,0 +1,398 @@ +// 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. + +// Test the basic StreamController and StreamController.singleSubscription. +import 'dart:async'; +import 'dart:isolate'; +import '../../../pkg/unittest/lib/unittest.dart'; +import 'event_helper.dart'; + +testController() { + // Test reduce + test("StreamController.reduce", () { + StreamController c = new StreamController(); + c.reduce(0, (a,b) => a + b) + .then(expectAsync1((int v) { + Expect.equals(42, v); + })); + c.add(10); + c.add(32); + c.close(); + }); + + test("StreamController.reduce throws", () { + StreamController c = new StreamController(); + c.reduce(0, (a,b) { throw "Fnyf!"; }) + .catchError(expectAsync1((e) { + Expect.equals("Fnyf!", e.error); + })); + c.add(42); + }); + + test("StreamController.pipeInto", () { + StreamController c = new StreamController(); + var list = []; + c.pipeInto(new CollectionSink(list)) + .then(expectAsync0(() { Expect.listEquals([1,2,9,3,9], list); })); + c.add(1); + c.add(2); + c.add(9); + c.add(3); + c.add(9); + c.close(); + }); +} + +testSingleController() { + test("Single-subscription StreamController.reduce", () { + StreamController c = new StreamController.singleSubscription(); + c.reduce(0, (a,b) => a + b) + .then(expectAsync1((int v) { Expect.equals(42, v); })); + c.add(10); + c.add(32); + c.close(); + }); + + test("Single-subscription StreamController.reduce throws", () { + StreamController c = new StreamController.singleSubscription(); + c.reduce(0, (a,b) { throw "Fnyf!"; }) + .catchError(expectAsync1((e) { Expect.equals("Fnyf!", e.error); })); + c.add(42); + }); + + test("Single-subscription StreamController.pipeInto", () { + StreamController c = new StreamController.singleSubscription(); + var list = []; + c.pipeInto(new CollectionSink(list)) + .then(expectAsync0(() { Expect.listEquals([1,2,9,3,9], list); })); + c.add(1); + c.add(2); + c.add(9); + c.add(3); + c.add(9); + c.close(); + }); + + test("Single-subscription StreamController subscription changes", () { + StreamController c = new StreamController.singleSubscription(); + StreamSink sink = c.sink; + Stream stream = c.stream; + int counter = 0; + var subscription; + subscription = stream.listen((data) { + counter += data; + Expect.throws(() => stream.listen(null), (e) => e is StateError); + subscription.cancel(); + stream.listen((data) { + counter += data * 10; + }, + onDone: expectAsync0(() { + Expect.equals(1 + 20, counter); + })); + }); + sink.add(1); + sink.add(2); + sink.close(); + }); + + test("Single-subscription StreamController events are buffered when" + " there is no subscriber", + () { + StreamController c = new StreamController.singleSubscription(); + StreamSink sink = c.sink; + Stream stream = c.stream; + int counter = 0; + sink.add(1); + sink.add(2); + sink.close(); + stream.listen( + (data) { + counter += data; + }, + onDone: expectAsync0(() { + Expect.equals(3, counter); + })); + }); + + // Test subscription changes while firing. + test("Single-subscription StreamController subscription changes while firing", + () { + StreamController c = new StreamController.singleSubscription(); + StreamSink sink = c.sink; + Stream stream = c.stream; + int counter = 0; + var subscription = stream.listen(null); + subscription.onData(expectAsync1((data) { + counter += data; + subscription.cancel(); + stream.listen((data) { + counter += 10 * data; + }, + onDone: expectAsync0(() { + Expect.equals(1 + 20 + 30 + 40 + 50, counter); + })); + Expect.throws(() => stream.listen(null), (e) => e is StateError); + })); + sink.add(1); // seen by stream 1 + sink.add(2); // seen by stream 10 and 100 + sink.add(3); // -"- + sink.add(4); // -"- + sink.add(5); // seen by stream 10 + sink.close(); + }); +} + +testExtraMethods() { + Events sentEvents = new Events()..add(7)..add(9)..add(13)..add(87)..close(); + + test("firstMatching", () { + StreamController c = new StreamController(); + Future f = c.firstMatching((x) => (x % 3) == 0); + f.then(expectAsync1((v) { Expect.equals(9, v); })); + sentEvents.replay(c); + }); + + test("firstMatching 2", () { + StreamController c = new StreamController(); + Future f = c.firstMatching((x) => (x % 4) == 0); + f.catchError(expectAsync1((e) {})); + sentEvents.replay(c); + }); + + test("firstMatching 3", () { + StreamController c = new StreamController(); + Future f = c.firstMatching((x) => (x % 4) == 0, defaultValue: () => 999); + f.then(expectAsync1((v) { Expect.equals(999, v); })); + sentEvents.replay(c); + }); + + + test("lastMatching", () { + StreamController c = new StreamController(); + Future f = c.lastMatching((x) => (x % 3) == 0); + f.then(expectAsync1((v) { Expect.equals(87, v); })); + sentEvents.replay(c); + }); + + test("lastMatching 2", () { + StreamController c = new StreamController(); + Future f = c.lastMatching((x) => (x % 4) == 0); + f.catchError(expectAsync1((e) {})); + sentEvents.replay(c); + }); + + test("lastMatching 3", () { + StreamController c = new StreamController(); + Future f = c.lastMatching((x) => (x % 4) == 0, defaultValue: () => 999); + f.then(expectAsync1((v) { Expect.equals(999, v); })); + sentEvents.replay(c); + }); + + test("singleMatching", () { + StreamController c = new StreamController(); + Future f = c.singleMatching((x) => (x % 9) == 0); + f.then(expectAsync1((v) { Expect.equals(9, v); })); + sentEvents.replay(c); + }); + + test("singleMatching 2", () { + StreamController c = new StreamController(); + Future f = c.singleMatching((x) => (x % 3) == 0); // Matches both 9 and 87.. + f.catchError(expectAsync1((e) { Expect.isTrue(e.error is StateError); })); + sentEvents.replay(c); + }); + + test("first", () { + StreamController c = new StreamController(); + Future f = c.first; + f.then(expectAsync1((v) { Expect.equals(7, v);})); + sentEvents.replay(c); + }); + + test("first empty", () { + StreamController c = new StreamController(); + Future f = c.first; + f.catchError(expectAsync1((e) { Expect.isTrue(e.error is StateError); })); + Events emptyEvents = new Events()..close(); + emptyEvents.replay(c); + }); + + test("first error", () { + StreamController c = new StreamController(); + Future f = c.first; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..error("error")..close(); + errorEvents.replay(c); + }); + + test("first error 2", () { + StreamController c = new StreamController(); + Future f = c.first; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..error("error")..error("error2")..close(); + errorEvents.replay(c); + }); + + test("last", () { + StreamController c = new StreamController(); + Future f = c.last; + f.then(expectAsync1((v) { Expect.equals(87, v);})); + sentEvents.replay(c); + }); + + test("last empty", () { + StreamController c = new StreamController(); + Future f = c.last; + f.catchError(expectAsync1((e) { Expect.isTrue(e.error is StateError); })); + Events emptyEvents = new Events()..close(); + emptyEvents.replay(c); + }); + + test("last error", () { + StreamController c = new StreamController(); + Future f = c.last; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..error("error")..close(); + errorEvents.replay(c); + }); + + test("last error 2", () { + StreamController c = new StreamController(); + Future f = c.last; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..error("error")..error("error2")..close(); + errorEvents.replay(c); + }); + + test("elementAt", () { + StreamController c = new StreamController(); + Future f = c.elementAt(2); + f.then(expectAsync1((v) { Expect.equals(13, v);})); + sentEvents.replay(c); + }); + + test("elementAt 2", () { + StreamController c = new StreamController(); + Future f = c.elementAt(20); + f.catchError(expectAsync1((e) { Expect.isTrue(e.error is StateError); })); + sentEvents.replay(c); + }); +} + +testPause() { + test("pause event-unpause", () { + StreamController c = new StreamController(); + Events actualEvents = new Events.capture(c); + Events expectedEvents = new Events(); + expectedEvents.add(42); + c.add(42); + Expect.listEquals(expectedEvents.events, actualEvents.events); + SignalCompleter completer = new SignalCompleter(); + actualEvents.pause(completer.signal); + c..add(43)..add(44)..close(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + completer.complete(); + expectedEvents..add(43)..add(44)..close(); + actualEvents.onDone(expectAsync0(() { + Expect.listEquals(expectedEvents.events, actualEvents.events); + })); + }); + + test("pause twice event-unpause", () { + StreamController c = new StreamController(); + Events actualEvents = new Events.capture(c); + Events expectedEvents = new Events(); + expectedEvents.add(42); + c.add(42); + Expect.listEquals(expectedEvents.events, actualEvents.events); + SignalCompleter completer = new SignalCompleter(); + SignalCompleter completer2 = new SignalCompleter(); + actualEvents.pause(completer.signal); + actualEvents.pause(completer2.signal); + c..add(43)..add(44)..close(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + completer.complete(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + completer2.complete(); + expectedEvents..add(43)..add(44)..close(); + actualEvents.onDone(expectAsync0((){ + Expect.listEquals(expectedEvents.events, actualEvents.events); + })); + }); + + test("pause twice direct-unpause", () { + StreamController c = new StreamController(); + Events actualEvents = new Events.capture(c); + Events expectedEvents = new Events(); + expectedEvents.add(42); + c.add(42); + Expect.listEquals(expectedEvents.events, actualEvents.events); + actualEvents.pause(); + actualEvents.pause(); + c.add(43); + c.add(44); + c.close(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + actualEvents.resume(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + expectedEvents..add(43)..add(44)..close(); + actualEvents.onDone(expectAsync0(() { + Expect.listEquals(expectedEvents.events, actualEvents.events); + })); + actualEvents.resume(); + }); + + test("pause twice direct-event-unpause", () { + StreamController c = new StreamController(); + Events actualEvents = new Events.capture(c); + Events expectedEvents = new Events(); + expectedEvents.add(42); + c.add(42); + Expect.listEquals(expectedEvents.events, actualEvents.events); + SignalCompleter completer = new SignalCompleter(); + actualEvents.pause(completer.signal); + actualEvents.pause(); + c.add(43); + c.add(44); + c.close(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + actualEvents.resume(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + expectedEvents..add(43)..add(44)..close(); + actualEvents.onDone(expectAsync0(() { + Expect.listEquals(expectedEvents.events, actualEvents.events); + })); + completer.complete(); + }); + + test("pause twice direct-unpause", () { + StreamController c = new StreamController(); + Events actualEvents = new Events.capture(c); + Events expectedEvents = new Events(); + expectedEvents.add(42); + c.add(42); + Expect.listEquals(expectedEvents.events, actualEvents.events); + SignalCompleter completer = new SignalCompleter(); + actualEvents.pause(completer.signal); + actualEvents.pause(); + c.add(43); + c.add(44); + c.close(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + completer.complete(); + Expect.listEquals(expectedEvents.events, actualEvents.events); + expectedEvents..add(43)..add(44)..close(); + actualEvents.onDone(expectAsync0(() { + Expect.listEquals(expectedEvents.events, actualEvents.events); + })); + actualEvents.resume(); + }); +} + +main() { + testController(); + testSingleController(); + testExtraMethods(); + testPause(); +} diff --git a/tests/lib/async/stream_controller_test.dart b/tests/lib/async/stream_controller_test.dart new file mode 100644 index 00000000000..e06ec4ad512 --- /dev/null +++ b/tests/lib/async/stream_controller_test.dart @@ -0,0 +1,359 @@ +// 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. + +// Test the basic StreamController and StreamController.singleSubscription. +import 'dart:async'; +import 'event_helper.dart'; + +testController() { + // Test normal flow. + var c = new StreamController(); + Events expectedEvents = new Events() + ..add(42) + ..add("dibs") + ..error("error!") + ..error("error too!") + ..close(); + Events actualEvents = new Events.capture(c); + expectedEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test automatic unsubscription on error. + c = new StreamController(); + expectedEvents = new Events()..add(42)..error("error"); + actualEvents = new Events.capture(c, unsubscribeOnError: true); + Events sentEvents = + new Events()..add(42)..error("error")..add("Are you there?"); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test manual unsubscription. + c = new StreamController(); + expectedEvents = new Events()..add(42)..error("error")..add(37); + actualEvents = new Events.capture(c, unsubscribeOnError: false); + expectedEvents.replay(c); + actualEvents.subscription.cancel(); + c.add("Are you there"); // Not sent to actualEvents. + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test filter. + c = new StreamController(); + expectedEvents = new Events() + ..add("a string")..add("another string")..close(); + sentEvents = new Events() + ..add("a string")..add(42)..add("another string")..close(); + actualEvents = new Events.capture(c.where((v) => v is String)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test map. + c = new StreamController(); + expectedEvents = new Events()..add("abab")..error("error")..close(); + sentEvents = new Events()..add("ab")..error("error")..close(); + actualEvents = new Events.capture(c.mappedBy((v) => "$v$v")); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test handleError. + c = new StreamController(); + expectedEvents = new Events()..add("ab")..error("[foo]"); + sentEvents = new Events()..add("ab")..error("foo")..add("ab")..close(); + actualEvents = new Events.capture(c.handleError((v) { + if (v.error is String) { + return new AsyncError("[${v.error}]", + "other stack"); + } + }), unsubscribeOnError: true); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // reduce is tested asynchronously and therefore not in this file. + + // Test expand + c = new StreamController(); + sentEvents = new Events()..add(3)..add(2)..add(4)..close(); + expectedEvents = new Events()..add(1)..add(2)..add(3) + ..add(1)..add(2) + ..add(1)..add(2)..add(3)..add(4) + ..close(); + actualEvents = new Events.capture(c.expand((v) { + var l = []; + for (int i = 0; i < v; i++) l.add(i + 1); + return l; + })); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test transform. + c = new StreamController(); + sentEvents = new Events()..add("a")..error(42)..add("b")..close(); + expectedEvents = + new Events()..error("a")..add(42)..error("b")..add("foo")..close(); + actualEvents = new Events.capture(c.transform(new StreamTransformer.from( + onData: (v, s) { s.signalError(new AsyncError(v)); }, + onError: (e, s) { s.add(e.error); }, + onDone: (s) { + s.add("foo"); + s.close(); + }))); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test multiple filters. + c = new StreamController(); + sentEvents = new Events()..add(42) + ..add("snugglefluffy") + ..add(7) + ..add("42") + ..error("not FormatException") // Unsubscribes. + ..close(); + expectedEvents = new Events()..add(42)..error("not FormatException"); + actualEvents = new Events.capture( + c.where((v) => v is String) + .mappedBy((v) => int.parse(v)) + .handleError((v) { + if (v.error is! FormatException) return v; + }) + .where((v) => v > 10), + unsubscribeOnError: true); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test subscription changes while firing. + c = new StreamController(); + var sink = c.sink; + var stream = c.stream; + var counter = 0; + var subscription = stream.listen(null); + subscription.onData((data) { + counter += data; + subscription.cancel(); + stream.listen((data) { + counter += 10 * data; + }); + var subscription2 = stream.listen(null); + subscription2.onData((data) { + counter += 100 * data; + if (data == 4) subscription2.cancel(); + }); + }); + sink.add(1); // seen by stream 1 + sink.add(2); // seen by stream 10 and 100 + sink.add(3); // -"- + sink.add(4); // -"- + sink.add(5); // seen by stream 10 + Expect.equals(1 + 20 + 200 + 30 + 300 + 40 + 400 + 50, counter); +} + +testSingleController() { + // Test normal flow. + var c = new StreamController.singleSubscription(); + Events expectedEvents = new Events() + ..add(42) + ..add("dibs") + ..error("error!") + ..error("error too!") + ..close(); + Events actualEvents = new Events.capture(c); + expectedEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test automatic unsubscription on error. + c = new StreamController.singleSubscription(); + expectedEvents = new Events()..add(42)..error("error"); + actualEvents = new Events.capture(c, unsubscribeOnError: true); + Events sentEvents = + new Events()..add(42)..error("error")..add("Are you there?"); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test manual unsubscription. + c = new StreamController.singleSubscription(); + expectedEvents = new Events()..add(42)..error("error")..add(37); + actualEvents = new Events.capture(c, unsubscribeOnError: false); + expectedEvents.replay(c); + actualEvents.subscription.cancel(); + c.add("Are you there"); // Not sent to actualEvents. + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test filter. + c = new StreamController.singleSubscription(); + expectedEvents = new Events() + ..add("a string")..add("another string")..close(); + sentEvents = new Events() + ..add("a string")..add(42)..add("another string")..close(); + actualEvents = new Events.capture(c.where((v) => v is String)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test map. + c = new StreamController.singleSubscription(); + expectedEvents = new Events()..add("abab")..error("error")..close(); + sentEvents = new Events()..add("ab")..error("error")..close(); + actualEvents = new Events.capture(c.mappedBy((v) => "$v$v")); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test handleError. + c = new StreamController.singleSubscription(); + expectedEvents = new Events()..add("ab")..error("[foo]"); + sentEvents = new Events()..add("ab")..error("foo")..add("ab")..close(); + actualEvents = new Events.capture(c.handleError((v) { + if (v.error is String) { + return new AsyncError("[${v.error}]", + "other stack"); + } + }), unsubscribeOnError: true); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // reduce is tested asynchronously and therefore not in this file. + + // Test expand + c = new StreamController.singleSubscription(); + sentEvents = new Events()..add(3)..add(2)..add(4)..close(); + expectedEvents = new Events()..add(1)..add(2)..add(3) + ..add(1)..add(2) + ..add(1)..add(2)..add(3)..add(4) + ..close(); + actualEvents = new Events.capture(c.expand((v) { + var l = []; + for (int i = 0; i < v; i++) l.add(i + 1); + return l; + })); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // pipe is tested asynchronously and therefore not in this file. + c = new StreamController.singleSubscription(); + var list = []; + c.pipeInto(new CollectionSink(list)) + .then(() { Expect.listEquals([1,2,9,3,9], list); }); + c.add(1); + c.add(2); + c.add(9); + c.add(3); + c.add(9); + c.close(); + + // Test transform. + c = new StreamController.singleSubscription(); + sentEvents = new Events()..add("a")..error(42)..add("b")..close(); + expectedEvents = + new Events()..error("a")..add(42)..error("b")..add("foo")..close(); + actualEvents = new Events.capture(c.transform(new StreamTransformer.from( + onData: (v, s) { s.signalError(new AsyncError(v)); }, + onError: (e, s) { s.add(e.error); }, + onDone: (s) { + s.add("foo"); + s.close(); + }))); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test multiple filters. + c = new StreamController.singleSubscription(); + sentEvents = new Events()..add(42) + ..add("snugglefluffy") + ..add(7) + ..add("42") + ..error("not FormatException") // Unsubscribes. + ..close(); + expectedEvents = new Events()..add(42)..error("not FormatException"); + actualEvents = new Events.capture( + c.where((v) => v is String) + .mappedBy((v) => int.parse(v)) + .handleError((v) { + if (v.error is! FormatException) return v; + }) + .where((v) => v > 10), + unsubscribeOnError: true); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + // Test that only one subscription is allowed. + c = new StreamController.singleSubscription(); + var sink = c.sink; + var stream = c.stream; + var counter = 0; + var subscription = stream.listen((data) { counter += data; }); + Expect.throws(() => stream.listen(null), (e) => e is StateError); + sink.add(1); + Expect.equals(1, counter); + c.close(); +} + +testExtraMethods() { + Events sentEvents = new Events()..add(1)..add(2)..add(3)..close(); + + var c = new StreamController(); + Events expectedEvents = new Events()..add(3)..close(); + Events actualEvents = new Events.capture(c.skip(2)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + c = new StreamController(); + expectedEvents = new Events()..close(); + actualEvents = new Events.capture(c.skip(3)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + c = new StreamController(); + expectedEvents = new Events()..close(); + actualEvents = new Events.capture(c.skip(7)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + c = new StreamController(); + expectedEvents = sentEvents; + actualEvents = new Events.capture(c.skip(0)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + + c = new StreamController(); + expectedEvents = new Events()..add(3)..close(); + actualEvents = new Events.capture(c.skipWhile((x) => x <= 2)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + + c = new StreamController(); + expectedEvents = new Events()..add(1)..add(2)..close(); + actualEvents = new Events.capture(c.take(2)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + + c = new StreamController(); + expectedEvents = new Events()..add(1)..add(2)..close(); + actualEvents = new Events.capture(c.takeWhile((x) => x <= 2)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + c = new StreamController(); + sentEvents = new Events() + ..add(1)..add(1)..add(2)..add(1)..add(2)..add(2)..add(2)..close(); + expectedEvents = new Events() + ..add(1)..add(2)..add(1)..add(2)..close(); + actualEvents = new Events.capture(c.distinct()); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); + + c = new StreamController(); + sentEvents = new Events() + ..add(5)..add(6)..add(4)..add(6)..add(8)..add(3)..add(4)..add(1)..close(); + expectedEvents = new Events() + ..add(5)..add(4)..add(3)..add(1)..close(); + // Use 'distinct' as a filter with access to the previously emitted event. + actualEvents = new Events.capture(c.distinct((a, b) => a < b)); + sentEvents.replay(c); + Expect.listEquals(expectedEvents.events, actualEvents.events); +} + +main() { + testController(); + testSingleController(); + testExtraMethods(); +} diff --git a/tests/lib/async/stream_min_max_test.dart b/tests/lib/async/stream_min_max_test.dart new file mode 100644 index 00000000000..471f3095e79 --- /dev/null +++ b/tests/lib/async/stream_min_max_test.dart @@ -0,0 +1,42 @@ +// 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. + +import 'dart:async'; +import 'dart:isolate'; +import '../../../pkg/unittest/lib/unittest.dart'; +import 'event_helper.dart'; + +const int big = 1000000; +const double inf = double.INFINITY; +List intList = const [-0, 0, -1, 1, -10, 10, -big, big]; +List doubleList = const [-0.0, 0.0, -1.0, 1.0, -10.0, 10.0, -inf, inf]; + +main() { + testMinMax(name, iterable, min, max, [int compare(a, b)]) { + test("$name-min", () { + StreamController c = new StreamController(); + Future f = c.min(compare); + f.then(expectAsync1((v) { Expect.equals(min, v);})); + new Events.fromIterable(iterable).replay(c); + }); + test("$name-max", () { + StreamController c = new StreamController(); + Future f = c.max(compare); + f.then(expectAsync1((v) { Expect.equals(max, v);})); + new Events.fromIterable(iterable).replay(c); + }); + } + + testMinMax("const-int", intList, -big, big); + testMinMax("list-int", intList.toList(), -big, big); + testMinMax("set-int", intList.toSet(), -big, big); + + testMinMax("const-double", doubleList, -inf, inf); + testMinMax("list-double", doubleList.toList(), -inf, inf); + testMinMax("set-double", doubleList.toSet(), -inf, inf); + + int reverse(a, b) => b.compareTo(a); + testMinMax("rev-int", intList, big, -big, reverse); + testMinMax("rev-double", doubleList, inf, -inf, reverse); +} diff --git a/tests/lib/async/stream_single_test.dart b/tests/lib/async/stream_single_test.dart new file mode 100644 index 00000000000..44127a6571f --- /dev/null +++ b/tests/lib/async/stream_single_test.dart @@ -0,0 +1,49 @@ +// 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. + +// Test the basic StreamController and StreamController.singleSubscription. +import 'dart:async'; +import 'dart:isolate'; +import '../../../pkg/unittest/lib/unittest.dart'; +import 'event_helper.dart'; + +main() { + test("single", () { + StreamController c = new StreamController(); + Future f = c.single; + f.then(expectAsync1((v) { Expect.equals(42, v);})); + new Events.fromIterable([42]).replay(c); + }); + + test("single empty", () { + StreamController c = new StreamController(); + Future f = c.single; + f.catchError(expectAsync1((e) { Expect.isTrue(e.error is StateError); })); + new Events.fromIterable([]).replay(c); + }); + + test("single error", () { + StreamController c = new StreamController(); + Future f = c.single; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..error("error")..close(); + errorEvents.replay(c); + }); + + test("single error 2", () { + StreamController c = new StreamController(); + Future f = c.single; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..error("error")..error("error2")..close(); + errorEvents.replay(c); + }); + + test("single error 3", () { + StreamController c = new StreamController(); + Future f = c.single; + f.catchError(expectAsync1((e) { Expect.equals("error", e.error); })); + Events errorEvents = new Events()..add(499)..error("error")..close(); + errorEvents.replay(c); + }); +} diff --git a/tests/lib/crypto/hmac_md5_test.dart b/tests/lib/crypto/hmac_md5_test.dart index f47c7109191..297314760be 100644 --- a/tests/lib/crypto/hmac_md5_test.dart +++ b/tests/lib/crypto/hmac_md5_test.dart @@ -99,7 +99,8 @@ var hmac_md5_macs = void testStandardVectors(inputs, keys, string_macs, macs) { for (var i = 0; i < inputs.length; i++) { var h = new HMAC(new MD5(), keys[i]); - var d = h.update(inputs[i]).digest(); + h.add(inputs[i]); + var d = h.close(); Expect.isTrue(CryptoUtils.bytesToHex(d).startsWith(string_macs[i]), '$i'); Expect.isTrue(h.verify(macs[i])); Expect.isFalse(h.verify(macs[(i+1)%macs.length])); diff --git a/tests/lib/crypto/hmac_sha1_test.dart b/tests/lib/crypto/hmac_sha1_test.dart index 1aec85d0199..8a87ceb2c98 100644 --- a/tests/lib/crypto/hmac_sha1_test.dart +++ b/tests/lib/crypto/hmac_sha1_test.dart @@ -11,7 +11,9 @@ part 'hmac_sha1_test_vectors.dart'; void testStandardVectors(inputs, keys, macs) { for (var i = 0; i < inputs.length; i++) { - var d = new HMAC(new SHA1(), keys[i]).update(inputs[i]).digest(); + var hmac = new HMAC(new SHA1(), keys[i]); + hmac.add(inputs[i]); + var d = hmac.close(); Expect.isTrue(CryptoUtils.bytesToHex(d).startsWith(macs[i]), '$i'); } } diff --git a/tests/lib/crypto/hmac_sha256_test.dart b/tests/lib/crypto/hmac_sha256_test.dart index 8b2deb5670c..bfd85b2bbda 100644 --- a/tests/lib/crypto/hmac_sha256_test.dart +++ b/tests/lib/crypto/hmac_sha256_test.dart @@ -11,7 +11,9 @@ part 'hmac_sha256_test_vectors.dart'; void testStandardVectors(inputs, keys, macs) { for (var i = 0; i < inputs.length; i++) { - var d = new HMAC(new SHA256(), keys[i]).update(inputs[i]).digest(); + var hmac = new HMAC(new SHA256(), keys[i]); + hmac.add(inputs[i]); + var d = hmac.close(); Expect.isTrue(CryptoUtils.bytesToHex(d).startsWith(macs[i]), '$i'); } } diff --git a/tests/lib/crypto/sha1_test.dart b/tests/lib/crypto/sha1_test.dart index ba3ed4dd40a..b9e90697c15 100644 --- a/tests/lib/crypto/sha1_test.dart +++ b/tests/lib/crypto/sha1_test.dart @@ -11,7 +11,7 @@ part 'sha1_long_test_vectors.dart'; part 'sha1_short_test_vectors.dart'; List createTestArr(int len) { - var arr = new List(len); + var arr = new List.fixedLength(len); for (var i = 0; i < len; i++) { arr[i] = i; } @@ -534,26 +534,30 @@ void test() { "11bca5b61fc1f6d59078ec5354bc6d9adecc0c5d", ]; for (var i = 0; i < expected_values.length; i++) { - var digest = new SHA1().update(createTestArr(i)).digest(); + var hash = new SHA1(); + hash.add(createTestArr(i)); + var digest = hash.close(); Expect.equals(expected_values[i], CryptoUtils.bytesToHex(digest)); } } void testInvalidUse() { var sha = new SHA1(); - sha.digest(); - Expect.throws(() => sha.update([0]), (e) => e is HashException); + sha.close(); + Expect.throws(() => sha.add([0]), (e) => e is HashException); } void testRepeatedDigest() { var sha = new SHA1(); - var digest = sha.digest(); - Expect.listEquals(digest, sha.digest()); + var digest = sha.close(); + Expect.listEquals(digest, sha.close()); } void testStandardVectors(inputs, mds) { for (var i = 0; i < inputs.length; i++) { - var d = new SHA1().update(inputs[i]).digest(); + var hash = new SHA1(); + hash.add(inputs[i]); + var d = hash.close(); Expect.equals(mds[i], CryptoUtils.bytesToHex(d), '$i'); } } diff --git a/tests/lib/crypto/sha256_test.dart b/tests/lib/crypto/sha256_test.dart index 44c92b1bf51..62a8dc942d5 100644 --- a/tests/lib/crypto/sha256_test.dart +++ b/tests/lib/crypto/sha256_test.dart @@ -11,7 +11,7 @@ part 'sha256_long_test_vectors.dart'; part 'sha256_short_test_vectors.dart'; List createTestArr(int len) { - var arr = new List(len); + var arr = new List.fixedLength(len); for (var i = 0; i < len; i++) { arr[i] = i; } @@ -278,26 +278,30 @@ void test() { '3f8591112c6bbe5c963965954e293108b7208ed2af893e500d859368c654eabe' ]; for (var i = 0; i < expected_values.length; i++) { - var d = new SHA256().update(createTestArr(i)).digest(); + var hash = new SHA256(); + hash.add(createTestArr(i)); + var d = hash.close(); Expect.equals(expected_values[i], CryptoUtils.bytesToHex(d), '$i'); } } void testInvalidUse() { var sha = new SHA256(); - sha.digest(); - Expect.throws(() => sha.update([0]), (e) => e is HashException); + sha.close(); + Expect.throws(() => sha.add([0]), (e) => e is HashException); } void testRepeatedDigest() { var sha = new SHA256(); - var digest = sha.digest(); - Expect.listEquals(digest, sha.digest()); + var digest = sha.close(); + Expect.listEquals(digest, sha.close()); } void testStandardVectors(inputs, mds) { for (var i = 0; i < inputs.length; i++) { - var d = new SHA256().update(inputs[i]).digest(); + var hash = new SHA256(); + hash.add(inputs[i]); + var d = hash.close(); Expect.equals(mds[i], CryptoUtils.bytesToHex(d), '$i'); } } diff --git a/tests/lib/math/math2_test.dart b/tests/lib/math/math2_test.dart index a2cc3a1ad4c..fb3c80489ec 100644 --- a/tests/lib/math/math2_test.dart +++ b/tests/lib/math/math2_test.dart @@ -156,7 +156,7 @@ class MathLibraryTest { static bool parseIntThrowsFormatException(str) { try { - math.parseInt(str); + int.parse(str); return false; } on FormatException catch (e) { return true; @@ -164,50 +164,50 @@ class MathLibraryTest { } static void testParseInt() { - Expect.equals(499, math.parseInt("499")); - Expect.equals(499, math.parseInt("+499")); - Expect.equals(-499, math.parseInt("-499")); - Expect.equals(499, math.parseInt(" 499 ")); - Expect.equals(499, math.parseInt(" +499 ")); - Expect.equals(-499, math.parseInt(" -499 ")); - Expect.equals(0, math.parseInt("0")); - Expect.equals(0, math.parseInt("+0")); - Expect.equals(0, math.parseInt("-0")); - Expect.equals(0, math.parseInt(" 0 ")); - Expect.equals(0, math.parseInt(" +0 ")); - Expect.equals(0, math.parseInt(" -0 ")); - Expect.equals(0x1234567890, math.parseInt("0x1234567890")); - Expect.equals(-0x1234567890, math.parseInt("-0x1234567890")); - Expect.equals(0x1234567890, math.parseInt(" 0x1234567890 ")); - Expect.equals(-0x1234567890, math.parseInt(" -0x1234567890 ")); - Expect.equals(256, math.parseInt("0x100")); - Expect.equals(-256, math.parseInt("-0x100")); - Expect.equals(256, math.parseInt(" 0x100 ")); - Expect.equals(-256, math.parseInt(" -0x100 ")); - Expect.equals(0xabcdef, math.parseInt("0xabcdef")); - Expect.equals(0xABCDEF, math.parseInt("0xABCDEF")); - Expect.equals(0xabcdef, math.parseInt("0xabCDEf")); - Expect.equals(-0xabcdef, math.parseInt("-0xabcdef")); - Expect.equals(-0xABCDEF, math.parseInt("-0xABCDEF")); - Expect.equals(0xabcdef, math.parseInt(" 0xabcdef ")); - Expect.equals(0xABCDEF, math.parseInt(" 0xABCDEF ")); - Expect.equals(-0xabcdef, math.parseInt(" -0xabcdef ")); - Expect.equals(-0xABCDEF, math.parseInt(" -0xABCDEF ")); - Expect.equals(0xabcdef, math.parseInt("0x00000abcdef")); - Expect.equals(0xABCDEF, math.parseInt("0x00000ABCDEF")); - Expect.equals(-0xabcdef, math.parseInt("-0x00000abcdef")); - Expect.equals(-0xABCDEF, math.parseInt("-0x00000ABCDEF")); - Expect.equals(0xabcdef, math.parseInt(" 0x00000abcdef ")); - Expect.equals(0xABCDEF, math.parseInt(" 0x00000ABCDEF ")); - Expect.equals(-0xabcdef, math.parseInt(" -0x00000abcdef ")); - Expect.equals(-0xABCDEF, math.parseInt(" -0x00000ABCDEF ")); - Expect.equals(10, math.parseInt("010")); - Expect.equals(-10, math.parseInt("-010")); - Expect.equals(10, math.parseInt(" 010 ")); - Expect.equals(-10, math.parseInt(" -010 ")); - Expect.equals(9, math.parseInt("09")); - Expect.equals(9, math.parseInt(" 09 ")); - Expect.equals(-9, math.parseInt("-09")); + Expect.equals(499, int.parse("499")); + Expect.equals(499, int.parse("+499")); + Expect.equals(-499, int.parse("-499")); + Expect.equals(499, int.parse(" 499 ")); + Expect.equals(499, int.parse(" +499 ")); + Expect.equals(-499, int.parse(" -499 ")); + Expect.equals(0, int.parse("0")); + Expect.equals(0, int.parse("+0")); + Expect.equals(0, int.parse("-0")); + Expect.equals(0, int.parse(" 0 ")); + Expect.equals(0, int.parse(" +0 ")); + Expect.equals(0, int.parse(" -0 ")); + Expect.equals(0x1234567890, int.parse("0x1234567890")); + Expect.equals(-0x1234567890, int.parse("-0x1234567890")); + Expect.equals(0x1234567890, int.parse(" 0x1234567890 ")); + Expect.equals(-0x1234567890, int.parse(" -0x1234567890 ")); + Expect.equals(256, int.parse("0x100")); + Expect.equals(-256, int.parse("-0x100")); + Expect.equals(256, int.parse(" 0x100 ")); + Expect.equals(-256, int.parse(" -0x100 ")); + Expect.equals(0xabcdef, int.parse("0xabcdef")); + Expect.equals(0xABCDEF, int.parse("0xABCDEF")); + Expect.equals(0xabcdef, int.parse("0xabCDEf")); + Expect.equals(-0xabcdef, int.parse("-0xabcdef")); + Expect.equals(-0xABCDEF, int.parse("-0xABCDEF")); + Expect.equals(0xabcdef, int.parse(" 0xabcdef ")); + Expect.equals(0xABCDEF, int.parse(" 0xABCDEF ")); + Expect.equals(-0xabcdef, int.parse(" -0xabcdef ")); + Expect.equals(-0xABCDEF, int.parse(" -0xABCDEF ")); + Expect.equals(0xabcdef, int.parse("0x00000abcdef")); + Expect.equals(0xABCDEF, int.parse("0x00000ABCDEF")); + Expect.equals(-0xabcdef, int.parse("-0x00000abcdef")); + Expect.equals(-0xABCDEF, int.parse("-0x00000ABCDEF")); + Expect.equals(0xabcdef, int.parse(" 0x00000abcdef ")); + Expect.equals(0xABCDEF, int.parse(" 0x00000ABCDEF ")); + Expect.equals(-0xabcdef, int.parse(" -0x00000abcdef ")); + Expect.equals(-0xABCDEF, int.parse(" -0x00000ABCDEF ")); + Expect.equals(10, int.parse("010")); + Expect.equals(-10, int.parse("-010")); + Expect.equals(10, int.parse(" 010 ")); + Expect.equals(-10, int.parse(" -010 ")); + Expect.equals(9, int.parse("09")); + Expect.equals(9, int.parse(" 09 ")); + Expect.equals(-9, int.parse("-09")); Expect.equals(true, parseIntThrowsFormatException("1b")); Expect.equals(true, parseIntThrowsFormatException(" 1b ")); Expect.equals(true, parseIntThrowsFormatException(" 1 b ")); diff --git a/tests/lib/math/math_parse_double_test.dart b/tests/lib/math/math_parse_double_test.dart index fe2393c7e16..fb6b3fac663 100644 --- a/tests/lib/math/math_parse_double_test.dart +++ b/tests/lib/math/math_parse_double_test.dart @@ -7,87 +7,85 @@ // class entirely. library math_parse_double_test; -import 'dart:math'; - void parseDoubleThrowsFormatException(str) { - Expect.throws(() => parseDouble(str), (e) => e is FormatException); + Expect.throws(() => double.parse(str), (e) => e is FormatException); } void main() { - Expect.equals(499.0, parseDouble("499")); - Expect.equals(499.0, parseDouble("499.0")); - Expect.equals(499.0, parseDouble("499.0")); - Expect.equals(499.0, parseDouble("+499")); - Expect.equals(-499.0, parseDouble("-499")); - Expect.equals(499.0, parseDouble(" 499 ")); - Expect.equals(499.0, parseDouble(" +499 ")); - Expect.equals(-499.0, parseDouble(" -499 ")); - Expect.equals(0.0, parseDouble("0")); - Expect.equals(0.0, parseDouble("+0")); - Expect.equals(-0.0, parseDouble("-0")); - Expect.equals(true, parseDouble("-0").isNegative); - Expect.equals(0.0, parseDouble(" 0 ")); - Expect.equals(0.0, parseDouble(" +0 ")); - Expect.equals(-0.0, parseDouble(" -0 ")); - Expect.equals(true, parseDouble(" -0 ").isNegative); - Expect.equals(1.0 * 0x1234567890, parseDouble("0x1234567890")); - Expect.equals(1.0 * -0x1234567890, parseDouble("-0x1234567890")); - Expect.equals(1.0 * 0x1234567890, parseDouble(" 0x1234567890 ")); - Expect.equals(1.0 * -0x1234567890, parseDouble(" -0x1234567890 ")); - Expect.equals(256.0, parseDouble("0x100")); - Expect.equals(-256.0, parseDouble("-0x100")); - Expect.equals(256.0, parseDouble(" 0x100 ")); - Expect.equals(-256.0, parseDouble(" -0x100 ")); - Expect.equals(1.0 * 0xabcdef, parseDouble("0xabcdef")); - Expect.equals(1.0 * 0xABCDEF, parseDouble("0xABCDEF")); - Expect.equals(1.0 * 0xabcdef, parseDouble("0xabCDEf")); - Expect.equals(1.0 * -0xabcdef, parseDouble("-0xabcdef")); - Expect.equals(1.0 * -0xABCDEF, parseDouble("-0xABCDEF")); - Expect.equals(1.0 * 0xabcdef, parseDouble(" 0xabcdef ")); - Expect.equals(1.0 * 0xABCDEF, parseDouble(" 0xABCDEF ")); - Expect.equals(1.0 * -0xabcdef, parseDouble(" -0xabcdef ")); - Expect.equals(1.0 * -0xABCDEF, parseDouble(" -0xABCDEF ")); - Expect.equals(1.0 * 0xabcdef, parseDouble("0x00000abcdef")); - Expect.equals(1.0 * 0xABCDEF, parseDouble("0x00000ABCDEF")); - Expect.equals(1.0 * -0xabcdef, parseDouble("-0x00000abcdef")); - Expect.equals(1.0 * -0xABCDEF, parseDouble("-0x00000ABCDEF")); - Expect.equals(1.0 * 0xabcdef, parseDouble(" 0x00000abcdef ")); - Expect.equals(1.0 * 0xABCDEF, parseDouble(" 0x00000ABCDEF ")); - Expect.equals(1.0 * -0xabcdef, parseDouble(" -0x00000abcdef ")); - Expect.equals(1.0 * -0xABCDEF, parseDouble(" -0x00000ABCDEF ")); - Expect.equals(10.0, parseDouble("010")); - Expect.equals(-10.0, parseDouble("-010")); - Expect.equals(10.0, parseDouble(" 010 ")); - Expect.equals(-10.0, parseDouble(" -010 ")); - Expect.equals(0.1, parseDouble("0.1")); - Expect.equals(0.1, parseDouble(" 0.1 ")); - Expect.equals(0.1, parseDouble(" +0.1 ")); - Expect.equals(-0.1, parseDouble(" -0.1 ")); - Expect.equals(0.1, parseDouble(".1")); - Expect.equals(0.1, parseDouble(" .1 ")); - Expect.equals(0.1, parseDouble(" +.1 ")); - Expect.equals(-0.1, parseDouble(" -.1 ")); - Expect.equals(1.5, parseDouble("1.5")); - Expect.equals(1234567.89, parseDouble("1234567.89")); - Expect.equals(1234567.89, parseDouble(" 1234567.89 ")); - Expect.equals(1234567.89, parseDouble(" +1234567.89 ")); - Expect.equals(-1234567.89, parseDouble(" -1234567.89 ")); - Expect.equals(1234567e89, parseDouble("1234567e89")); - Expect.equals(1234567e89, parseDouble(" 1234567e89 ")); - Expect.equals(1234567e89, parseDouble(" +1234567e89 ")); - Expect.equals(-1234567e89, parseDouble(" -1234567e89 ")); - Expect.equals(1234567.89e2, parseDouble("1234567.89e2")); - Expect.equals(1234567.89e2, parseDouble(" 1234567.89e2 ")); - Expect.equals(1234567.89e2, parseDouble(" +1234567.89e2 ")); - Expect.equals(-1234567.89e2, parseDouble(" -1234567.89e2 ")); - Expect.equals(1234567.89e2, parseDouble("1234567.89E2")); - Expect.equals(1234567.89e2, parseDouble(" 1234567.89E2 ")); - Expect.equals(1234567.89e2, parseDouble(" +1234567.89E2 ")); - Expect.equals(-1234567.89e2, parseDouble(" -1234567.89E2 ")); - Expect.equals(1234567.89e-2, parseDouble("1234567.89e-2")); - Expect.equals(1234567.89e-2, parseDouble(" 1234567.89e-2 ")); - Expect.equals(1234567.89e-2, parseDouble(" +1234567.89e-2 ")); - Expect.equals(-1234567.89e-2, parseDouble(" -1234567.89e-2 ")); + Expect.equals(499.0, double.parse("499")); + Expect.equals(499.0, double.parse("499.0")); + Expect.equals(499.0, double.parse("499.0")); + Expect.equals(499.0, double.parse("+499")); + Expect.equals(-499.0, double.parse("-499")); + Expect.equals(499.0, double.parse(" 499 ")); + Expect.equals(499.0, double.parse(" +499 ")); + Expect.equals(-499.0, double.parse(" -499 ")); + Expect.equals(0.0, double.parse("0")); + Expect.equals(0.0, double.parse("+0")); + Expect.equals(-0.0, double.parse("-0")); + Expect.equals(true, double.parse("-0").isNegative); + Expect.equals(0.0, double.parse(" 0 ")); + Expect.equals(0.0, double.parse(" +0 ")); + Expect.equals(-0.0, double.parse(" -0 ")); + Expect.equals(true, double.parse(" -0 ").isNegative); + Expect.equals(1.0 * 0x1234567890, double.parse("0x1234567890")); + Expect.equals(1.0 * -0x1234567890, double.parse("-0x1234567890")); + Expect.equals(1.0 * 0x1234567890, double.parse(" 0x1234567890 ")); + Expect.equals(1.0 * -0x1234567890, double.parse(" -0x1234567890 ")); + Expect.equals(256.0, double.parse("0x100")); + Expect.equals(-256.0, double.parse("-0x100")); + Expect.equals(256.0, double.parse(" 0x100 ")); + Expect.equals(-256.0, double.parse(" -0x100 ")); + Expect.equals(1.0 * 0xabcdef, double.parse("0xabcdef")); + Expect.equals(1.0 * 0xABCDEF, double.parse("0xABCDEF")); + Expect.equals(1.0 * 0xabcdef, double.parse("0xabCDEf")); + Expect.equals(1.0 * -0xabcdef, double.parse("-0xabcdef")); + Expect.equals(1.0 * -0xABCDEF, double.parse("-0xABCDEF")); + Expect.equals(1.0 * 0xabcdef, double.parse(" 0xabcdef ")); + Expect.equals(1.0 * 0xABCDEF, double.parse(" 0xABCDEF ")); + Expect.equals(1.0 * -0xabcdef, double.parse(" -0xabcdef ")); + Expect.equals(1.0 * -0xABCDEF, double.parse(" -0xABCDEF ")); + Expect.equals(1.0 * 0xabcdef, double.parse("0x00000abcdef")); + Expect.equals(1.0 * 0xABCDEF, double.parse("0x00000ABCDEF")); + Expect.equals(1.0 * -0xabcdef, double.parse("-0x00000abcdef")); + Expect.equals(1.0 * -0xABCDEF, double.parse("-0x00000ABCDEF")); + Expect.equals(1.0 * 0xabcdef, double.parse(" 0x00000abcdef ")); + Expect.equals(1.0 * 0xABCDEF, double.parse(" 0x00000ABCDEF ")); + Expect.equals(1.0 * -0xabcdef, double.parse(" -0x00000abcdef ")); + Expect.equals(1.0 * -0xABCDEF, double.parse(" -0x00000ABCDEF ")); + Expect.equals(10.0, double.parse("010")); + Expect.equals(-10.0, double.parse("-010")); + Expect.equals(10.0, double.parse(" 010 ")); + Expect.equals(-10.0, double.parse(" -010 ")); + Expect.equals(0.1, double.parse("0.1")); + Expect.equals(0.1, double.parse(" 0.1 ")); + Expect.equals(0.1, double.parse(" +0.1 ")); + Expect.equals(-0.1, double.parse(" -0.1 ")); + Expect.equals(0.1, double.parse(".1")); + Expect.equals(0.1, double.parse(" .1 ")); + Expect.equals(0.1, double.parse(" +.1 ")); + Expect.equals(-0.1, double.parse(" -.1 ")); + Expect.equals(1.5, double.parse("1.5")); + Expect.equals(1234567.89, double.parse("1234567.89")); + Expect.equals(1234567.89, double.parse(" 1234567.89 ")); + Expect.equals(1234567.89, double.parse(" +1234567.89 ")); + Expect.equals(-1234567.89, double.parse(" -1234567.89 ")); + Expect.equals(1234567e89, double.parse("1234567e89")); + Expect.equals(1234567e89, double.parse(" 1234567e89 ")); + Expect.equals(1234567e89, double.parse(" +1234567e89 ")); + Expect.equals(-1234567e89, double.parse(" -1234567e89 ")); + Expect.equals(1234567.89e2, double.parse("1234567.89e2")); + Expect.equals(1234567.89e2, double.parse(" 1234567.89e2 ")); + Expect.equals(1234567.89e2, double.parse(" +1234567.89e2 ")); + Expect.equals(-1234567.89e2, double.parse(" -1234567.89e2 ")); + Expect.equals(1234567.89e2, double.parse("1234567.89E2")); + Expect.equals(1234567.89e2, double.parse(" 1234567.89E2 ")); + Expect.equals(1234567.89e2, double.parse(" +1234567.89E2 ")); + Expect.equals(-1234567.89e2, double.parse(" -1234567.89E2 ")); + Expect.equals(1234567.89e-2, double.parse("1234567.89e-2")); + Expect.equals(1234567.89e-2, double.parse(" 1234567.89e-2 ")); + Expect.equals(1234567.89e-2, double.parse(" +1234567.89e-2 ")); + Expect.equals(-1234567.89e-2, double.parse(" -1234567.89e-2 ")); // TODO(floitsch): add tests for NaN and Infinity. parseDoubleThrowsFormatException("1b"); parseDoubleThrowsFormatException(" 1b "); diff --git a/tests/lib/math/math_test.dart b/tests/lib/math/math_test.dart index 9804138e00c..cfd2af65c00 100644 --- a/tests/lib/math/math_test.dart +++ b/tests/lib/math/math_test.dart @@ -153,7 +153,7 @@ class MathTest { static bool parseIntThrowsFormatException(str) { try { - parseInt(str); + int.parse(str); return false; } on FormatException catch (e) { return true; @@ -161,50 +161,50 @@ class MathTest { } static void testParseInt() { - Expect.equals(499, parseInt("499")); - Expect.equals(499, parseInt("+499")); - Expect.equals(-499, parseInt("-499")); - Expect.equals(499, parseInt(" 499 ")); - Expect.equals(499, parseInt(" +499 ")); - Expect.equals(-499, parseInt(" -499 ")); - Expect.equals(0, parseInt("0")); - Expect.equals(0, parseInt("+0")); - Expect.equals(0, parseInt("-0")); - Expect.equals(0, parseInt(" 0 ")); - Expect.equals(0, parseInt(" +0 ")); - Expect.equals(0, parseInt(" -0 ")); - Expect.equals(0x1234567890, parseInt("0x1234567890")); - Expect.equals(-0x1234567890, parseInt("-0x1234567890")); - Expect.equals(0x1234567890, parseInt(" 0x1234567890 ")); - Expect.equals(-0x1234567890, parseInt(" -0x1234567890 ")); - Expect.equals(256, parseInt("0x100")); - Expect.equals(-256, parseInt("-0x100")); - Expect.equals(256, parseInt(" 0x100 ")); - Expect.equals(-256, parseInt(" -0x100 ")); - Expect.equals(0xabcdef, parseInt("0xabcdef")); - Expect.equals(0xABCDEF, parseInt("0xABCDEF")); - Expect.equals(0xabcdef, parseInt("0xabCDEf")); - Expect.equals(-0xabcdef, parseInt("-0xabcdef")); - Expect.equals(-0xABCDEF, parseInt("-0xABCDEF")); - Expect.equals(0xabcdef, parseInt(" 0xabcdef ")); - Expect.equals(0xABCDEF, parseInt(" 0xABCDEF ")); - Expect.equals(-0xabcdef, parseInt(" -0xabcdef ")); - Expect.equals(-0xABCDEF, parseInt(" -0xABCDEF ")); - Expect.equals(0xabcdef, parseInt("0x00000abcdef")); - Expect.equals(0xABCDEF, parseInt("0x00000ABCDEF")); - Expect.equals(-0xabcdef, parseInt("-0x00000abcdef")); - Expect.equals(-0xABCDEF, parseInt("-0x00000ABCDEF")); - Expect.equals(0xabcdef, parseInt(" 0x00000abcdef ")); - Expect.equals(0xABCDEF, parseInt(" 0x00000ABCDEF ")); - Expect.equals(-0xabcdef, parseInt(" -0x00000abcdef ")); - Expect.equals(-0xABCDEF, parseInt(" -0x00000ABCDEF ")); - Expect.equals(10, parseInt("010")); - Expect.equals(-10, parseInt("-010")); - Expect.equals(10, parseInt(" 010 ")); - Expect.equals(-10, parseInt(" -010 ")); - Expect.equals(9, parseInt("09")); - Expect.equals(9, parseInt(" 09 ")); - Expect.equals(-9, parseInt("-09")); + Expect.equals(499, int.parse("499")); + Expect.equals(499, int.parse("+499")); + Expect.equals(-499, int.parse("-499")); + Expect.equals(499, int.parse(" 499 ")); + Expect.equals(499, int.parse(" +499 ")); + Expect.equals(-499, int.parse(" -499 ")); + Expect.equals(0, int.parse("0")); + Expect.equals(0, int.parse("+0")); + Expect.equals(0, int.parse("-0")); + Expect.equals(0, int.parse(" 0 ")); + Expect.equals(0, int.parse(" +0 ")); + Expect.equals(0, int.parse(" -0 ")); + Expect.equals(0x1234567890, int.parse("0x1234567890")); + Expect.equals(-0x1234567890, int.parse("-0x1234567890")); + Expect.equals(0x1234567890, int.parse(" 0x1234567890 ")); + Expect.equals(-0x1234567890, int.parse(" -0x1234567890 ")); + Expect.equals(256, int.parse("0x100")); + Expect.equals(-256, int.parse("-0x100")); + Expect.equals(256, int.parse(" 0x100 ")); + Expect.equals(-256, int.parse(" -0x100 ")); + Expect.equals(0xabcdef, int.parse("0xabcdef")); + Expect.equals(0xABCDEF, int.parse("0xABCDEF")); + Expect.equals(0xabcdef, int.parse("0xabCDEf")); + Expect.equals(-0xabcdef, int.parse("-0xabcdef")); + Expect.equals(-0xABCDEF, int.parse("-0xABCDEF")); + Expect.equals(0xabcdef, int.parse(" 0xabcdef ")); + Expect.equals(0xABCDEF, int.parse(" 0xABCDEF ")); + Expect.equals(-0xabcdef, int.parse(" -0xabcdef ")); + Expect.equals(-0xABCDEF, int.parse(" -0xABCDEF ")); + Expect.equals(0xabcdef, int.parse("0x00000abcdef")); + Expect.equals(0xABCDEF, int.parse("0x00000ABCDEF")); + Expect.equals(-0xabcdef, int.parse("-0x00000abcdef")); + Expect.equals(-0xABCDEF, int.parse("-0x00000ABCDEF")); + Expect.equals(0xabcdef, int.parse(" 0x00000abcdef ")); + Expect.equals(0xABCDEF, int.parse(" 0x00000ABCDEF ")); + Expect.equals(-0xabcdef, int.parse(" -0x00000abcdef ")); + Expect.equals(-0xABCDEF, int.parse(" -0x00000ABCDEF ")); + Expect.equals(10, int.parse("010")); + Expect.equals(-10, int.parse("-010")); + Expect.equals(10, int.parse(" 010 ")); + Expect.equals(-10, int.parse(" -010 ")); + Expect.equals(9, int.parse("09")); + Expect.equals(9, int.parse(" 09 ")); + Expect.equals(-9, int.parse("-09")); Expect.equals(true, parseIntThrowsFormatException("1b")); Expect.equals(true, parseIntThrowsFormatException(" 1b ")); Expect.equals(true, parseIntThrowsFormatException(" 1 b ")); diff --git a/tests/standalone/io/chunked_stream_test.dart b/tests/standalone/io/chunked_stream_test.dart index 9b4d00cf44b..2f343786db7 100644 --- a/tests/standalone/io/chunked_stream_test.dart +++ b/tests/standalone/io/chunked_stream_test.dart @@ -54,7 +54,7 @@ void test1() { } var _16k = 1024 * 16; - var data = new List(_16k); + var data = new List.fixedLength(_16k); for (int i = 0; i < _16k; i++) { data[i] = i % 256; } void testDone(int byteCount) { diff --git a/tests/standalone/io/dart_std_io_pipe_test.dart b/tests/standalone/io/dart_std_io_pipe_test.dart index e39e65ea709..967c48ab14a 100644 --- a/tests/standalone/io/dart_std_io_pipe_test.dart +++ b/tests/standalone/io/dart_std_io_pipe_test.dart @@ -23,7 +23,7 @@ void checkFileEmpty(String fileName) { void checkFileContent(String fileName, String content) { RandomAccessFile pipeOut = new File(fileName).openSync(); int length = pipeOut.lengthSync(); - List data = new List(length); + List data = new List.fixedLength(length); pipeOut.readListSync(data, 0, length); Expect.equals(content, new String.fromCharCodes(data)); pipeOut.closeSync(); @@ -71,9 +71,9 @@ void test(String shellScript, String dartScript, String type) { process.stdout.onData = process.stdout.read; process.stderr.onData = process.stderr.read; }); - future.handleException((ProcessException error) { + future.catchError((error) { dir.deleteSync(recursive: true); - Expect.fail(error.toString()); + Expect.fail(error.error.toString()); }); } diff --git a/tests/standalone/io/directory_error_test.dart b/tests/standalone/io/directory_error_test.dart index 3c26749f0c6..ed2b60c245b 100644 --- a/tests/standalone/io/directory_error_test.dart +++ b/tests/standalone/io/directory_error_test.dart @@ -33,10 +33,9 @@ void testCreateInNonExistent(Directory temp, Function done) { Expect.throws(() => inNonExistent.createSync(), (e) => checkCreateInNonExistentFileException(e)); - inNonExistent.create().handleException((e) { - checkCreateInNonExistentFileException(e); + inNonExistent.create().catchError((e) { + checkCreateInNonExistentFileException(e.error); done(); - return true; }); } @@ -61,10 +60,9 @@ void testCreateTempInNonExistent(Directory temp, Function done) { Expect.throws(() => nonExistent.createTempSync(), (e) => checkCreateTempInNonExistentFileException(e)); - nonExistent.createTemp().handleException((e) { - checkCreateTempInNonExistentFileException(e); + nonExistent.createTemp().catchError((e) { + checkCreateTempInNonExistentFileException(e.error); done(); - return true; }); } @@ -84,10 +82,9 @@ void testDeleteNonExistent(Directory temp, Function done) { Expect.throws(() => nonExistent.deleteSync(), (e) => checkDeleteNonExistentFileException(e)); - nonExistent.delete().handleException((e) { - checkDeleteNonExistentFileException(e); + nonExistent.delete().catchError((e) { + checkDeleteNonExistentFileException(e.error); done(); - return true; }); } @@ -113,10 +110,9 @@ void testDeleteRecursivelyNonExistent(Directory temp, Function done) { Expect.throws(() => nonExistent.deleteSync(recursive: true), (e) => checkDeleteRecursivelyNonExistentFileException(e)); - nonExistent.delete(recursive: true).handleException((e) { - checkDeleteRecursivelyNonExistentFileException(e); + nonExistent.delete(recursive: true).catchError((e) { + checkDeleteRecursivelyNonExistentFileException(e.error); done(); - return true; }); } @@ -154,11 +150,10 @@ void testRenameNonExistent(Directory temp, Function done) { Expect.throws(() => nonExistent.renameSync(newPath), (e) => e is DirectoryIOException); var renameDone = nonExistent.rename(newPath); - renameDone.then((ignore) => Expect.fail('rename non existent')); - renameDone.handleException((e) { - Expect.isTrue(e is DirectoryIOException); - done(); - return true; + renameDone.then((ignore) => Expect.fail('rename non existent')) + .catchError((e) { + Expect.isTrue(e.error is DirectoryIOException); + done(); }); } @@ -171,12 +166,11 @@ void testRenameFileAsDirectory(Directory temp, Function done) { Expect.throws(() => d.renameSync(newPath), (e) => e is DirectoryIOException); var renameDone = d.rename(newPath); - renameDone.then((ignore) => Expect.fail('rename file as directory')); - renameDone.handleException((e) { - Expect.isTrue(e is DirectoryIOException); - done(); - return true; - }); + renameDone.then((ignore) => Expect.fail('rename file as directory')) + .catchError((e) { + Expect.isTrue(e.error is DirectoryIOException); + done(); + }); } @@ -188,13 +182,12 @@ testRenameOverwriteFile(Directory temp, Function done) { Expect.throws(() => temp1.renameSync(fileName), (e) => e is DirectoryIOException); var renameDone = temp1.rename(fileName); - renameDone.then((ignore) => Expect.fail('rename dir overwrite file')); - renameDone.handleException((e) { - Expect.isTrue(e is DirectoryIOException); - temp1.deleteSync(recursive: true); - done(); - return true; - }); + renameDone.then((ignore) => Expect.fail('rename dir overwrite file')) + .catchError((e) { + Expect.isTrue(e.error is DirectoryIOException); + temp1.deleteSync(recursive: true); + done(); + }); } diff --git a/tests/standalone/io/directory_fuzz_test.dart b/tests/standalone/io/directory_fuzz_test.dart index dd6fe0d1473..116f91802f2 100644 --- a/tests/standalone/io/directory_fuzz_test.dart +++ b/tests/standalone/io/directory_fuzz_test.dart @@ -5,10 +5,11 @@ // 'fuzz' test the directory APIs by providing unexpected type // arguments. The test passes if the VM does not crash. -import "dart:io"; -import "dart:isolate"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; -import "fuzz_support.dart"; +import 'fuzz_support.dart'; fuzzSyncMethods() { typeMapping.forEach((k, v) { @@ -44,12 +45,12 @@ fuzzAsyncMethods() { futures.add(doItAsync(d.create)); futures.add(doItAsync(d.delete)); futures.add(doItAsync(() { - return d.createTemp().chain((temp) { + return d.createTemp().then((temp) { return temp.delete(); }); })); futures.add(doItAsync(() { - return d.exists().chain((res) { + return d.exists().then((res) { if (!res) return d.delete(recursive: true); return new Future.immediate(true); }); diff --git a/tests/standalone/io/directory_test.dart b/tests/standalone/io/directory_test.dart index 825cb9cf285..b25907119fc 100644 --- a/tests/standalone/io/directory_test.dart +++ b/tests/standalone/io/directory_test.dart @@ -143,12 +143,10 @@ class DirectoryTest { static void testDeleteNonExistent() { // Test that deleting a non-existing directory fails. setupFutureHandlers(future) { - future.handleException((e) { - Expect.isTrue(e is DirectoryIOException); - return true; - }); future.then((ignore) { Expect.fail("Deletion of non-existing directory should fail"); + }).catchError((e) { + Expect.isTrue(e.error is DirectoryIOException); }); } @@ -176,14 +174,14 @@ class DirectoryTest { var long = new Directory("${buffer.toString()}"); var errors = 0; onError(e) { - Expect.isTrue(e is DirectoryIOException); + Expect.isTrue(e.error is DirectoryIOException); if (++errors == 2) { d.delete(recursive: true).then((ignore) => port.close()); } return true; } - long.delete().handleException(onError); - long.delete(recursive: true).handleException(onError); + long.delete().catchError(onError); + long.delete(recursive: true).catchError(onError); }); }); } @@ -482,7 +480,7 @@ testCreateTempError() { var port = new ReceivePort(); var future = new Directory(location).createTemp(); - future.handleException((e) => port.close()); + future.catchError((e) => port.close()); } @@ -550,14 +548,13 @@ testCreateDirExistingFile() { var subDir = new Directory(path); file.create().then((_) { subDir.create() - ..then((_) { Expect.fail("dir create should fail on existing file"); }) - ..handleException((e) { - Expect.isTrue(e is DirectoryIOException); - temp.delete(recursive: true).then((_) { - port.close(); - }); - return true; + .then((_) { Expect.fail("dir create should fail on existing file"); }) + .catchError((e) { + Expect.isTrue(e.error is DirectoryIOException); + temp.delete(recursive: true).then((_) { + port.close(); }); + }); }); }); } diff --git a/tests/standalone/io/echo_server_stream_test.dart b/tests/standalone/io/echo_server_stream_test.dart index 200dfd523e8..a350b59b826 100644 --- a/tests/standalone/io/echo_server_stream_test.dart +++ b/tests/standalone/io/echo_server_stream_test.dart @@ -24,7 +24,7 @@ class EchoServerGame { EchoServerGame.start() : _receivePort = new ReceivePort(), _sendPort = null, - _buffer = new List(MSGSIZE), + _buffer = new List.fixedLength(MSGSIZE), _messages = 0 { for (int i = 0; i < MSGSIZE; i++) { _buffer[i] = FIRSTCHAR + i; @@ -77,7 +77,7 @@ class EchoServerGame { offset += bytesRead; } - if (_messages % 2 == 0) data = new List(MSGSIZE); + if (_messages % 2 == 0) data = new List.fixedLength(MSGSIZE); inputStream.onData = onData; inputStream.onClosed = onClosed; } @@ -147,7 +147,7 @@ class EchoServer extends TestingServer { void onConnection(Socket connection) { InputStream inputStream; - List buffer = new List(MSGSIZE); + List buffer = new List.fixedLength(MSGSIZE); int offset = 0; void dataReceived() { diff --git a/tests/standalone/io/echo_server_test.dart b/tests/standalone/io/echo_server_test.dart index 27c31282960..4208bb8663c 100644 --- a/tests/standalone/io/echo_server_test.dart +++ b/tests/standalone/io/echo_server_test.dart @@ -30,7 +30,7 @@ class EchoServerGame { EchoServerGame.start() : _receivePort = new ReceivePort(), _sendPort = null, - _buffer = new List(MSGSIZE), + _buffer = new List.fixedLength(MSGSIZE), _messages = 0 { for (int i = 0; i < MSGSIZE; i++) { _buffer[i] = FIRSTCHAR + i; @@ -44,7 +44,7 @@ class EchoServerGame { void messageHandler() { - List bufferReceived = new List(MSGSIZE); + List bufferReceived = new List.fixedLength(MSGSIZE); int bytesRead = 0; void handleRead() { @@ -141,7 +141,7 @@ class EchoServer extends TestingServer { void messageHandler() { - List buffer = new List(msgSize); + List buffer = new List.fixedLength(msgSize); int bytesRead = 0; void handleRead() { diff --git a/tests/standalone/io/file_error_test.dart b/tests/standalone/io/file_error_test.dart index 4cda95af8c5..59ad3910334 100644 --- a/tests/standalone/io/file_error_test.dart +++ b/tests/standalone/io/file_error_test.dart @@ -51,12 +51,11 @@ void testOpenNonExistent() { (e) => checkOpenNonExistentFileException(e)); var openFuture = file.open(FileMode.READ); - openFuture.then((raf) => Expect.fail("Unreachable code")); - openFuture.handleException((e) { - checkOpenNonExistentFileException(e); - p.toSendPort().send(null); - return true; - }); + openFuture.then((raf) => Expect.fail("Unreachable code")) + .catchError((e) { + checkOpenNonExistentFileException(e.error); + p.toSendPort().send(null); + }); } @@ -74,12 +73,11 @@ void testDeleteNonExistent() { (e) => checkDeleteNonExistentFileException(e)); var delete = file.delete(); - delete.then((ignore) => Expect.fail("Unreachable code")); - delete.handleException((e) { - checkDeleteNonExistentFileException(e); - p.toSendPort().send(null); - return true; - }); + delete.then((ignore) => Expect.fail("Unreachable code")) + .catchError((e) { + checkDeleteNonExistentFileException(e.error); + p.toSendPort().send(null); + }); } @@ -97,12 +95,11 @@ void testLengthNonExistent() { (e) => checkLengthNonExistentFileException(e)); var lenFuture = file.length(); - lenFuture.then((len) => Expect.fail("Unreachable code")); - lenFuture.handleException((e) { - checkLengthNonExistentFileException(e); - p.toSendPort().send(null); - return true; - }); + lenFuture.then((len) => Expect.fail("Unreachable code")) + .catchError((e) { + checkLengthNonExistentFileException(e.error); + p.toSendPort().send(null); + }); } @@ -135,11 +132,10 @@ void testCreateInNonExistentDirectory() { (e) => checkCreateInNonExistentDirectoryException(e)); var create = file.create(); - create.then((ignore) => Expect.fail("Unreachable code")); - create.handleException((e) { - checkCreateInNonExistentDirectoryException(e); + create.then((ignore) => Expect.fail("Unreachable code")) + .catchError((e) { + checkCreateInNonExistentDirectoryException(e.error); p.toSendPort().send(null); - return true; }); } @@ -167,11 +163,10 @@ void testFullPathOnNonExistentDirectory() { (e) => checkFullPathOnNonExistentDirectoryException(e)); var fullPathFuture = file.fullPath(); - fullPathFuture.then((path) => Expect.fail("Unreachable code $path")); - fullPathFuture.handleException((e) { - checkFullPathOnNonExistentDirectoryException(e); + fullPathFuture.then((path) => Expect.fail("Unreachable code $path")) + .catchError((e) { + checkFullPathOnNonExistentDirectoryException(e.error); p.toSendPort().send(null); - return true; }); } @@ -200,11 +195,10 @@ void testDirectoryInNonExistentDirectory() { (e) => checkDirectoryInNonExistentDirectoryException(e)); var dirFuture = file.directory(); - dirFuture.then((directory) => Expect.fail("Unreachable code")); - dirFuture.handleException((e) { - checkDirectoryInNonExistentDirectoryException(e); + dirFuture.then((directory) => Expect.fail("Unreachable code")) + .catchError((e) { + checkDirectoryInNonExistentDirectoryException(e.error); p.toSendPort().send(null); - return true; }); } @@ -222,11 +216,10 @@ void testReadAsBytesNonExistent() { (e) => checkOpenNonExistentFileException(e)); var readAsBytesFuture = file.readAsBytes(); - readAsBytesFuture.then((data) => Expect.fail("Unreachable code")); - readAsBytesFuture.handleException((e) { - checkOpenNonExistentFileException(e); + readAsBytesFuture.then((data) => Expect.fail("Unreachable code")) + .catchError((e) { + checkOpenNonExistentFileException(e.error); p.toSendPort().send(null); - return true; }); } @@ -244,11 +237,10 @@ void testReadAsTextNonExistent() { (e) => checkOpenNonExistentFileException(e)); var readAsStringFuture = file.readAsString(Encoding.ASCII); - readAsStringFuture.then((data) => Expect.fail("Unreachable code")); - readAsStringFuture.handleException((e) { - checkOpenNonExistentFileException(e); + readAsStringFuture.then((data) => Expect.fail("Unreachable code")) + .catchError((e) { + checkOpenNonExistentFileException(e.error); p.toSendPort().send(null); - return true; }); } @@ -266,11 +258,10 @@ testReadAsLinesNonExistent() { (e) => checkOpenNonExistentFileException(e)); var readAsLinesFuture = file.readAsLines(Encoding.ASCII); - readAsLinesFuture.then((data) => Expect.fail("Unreachable code")); - readAsLinesFuture.handleException((e) { - checkOpenNonExistentFileException(e); + readAsLinesFuture.then((data) => Expect.fail("Unreachable code")) + .catchError((e) { + checkOpenNonExistentFileException(e.error); p.toSendPort().send(null); - return true; }); } @@ -308,10 +299,9 @@ testWriteByteToReadOnlyFile() { (e) => checkWriteReadOnlyFileException(e)); var writeByteFuture = openedFile.writeByte(0); - writeByteFuture.handleException((e) { - checkWriteReadOnlyFileException(e); + writeByteFuture.catchError((e) { + checkWriteReadOnlyFileException(e.error); openedFile.close().then((ignore) => port.send(null)); - return true; }); }); } @@ -326,10 +316,9 @@ testWriteListToReadOnlyFile() { (e) => checkWriteReadOnlyFileException(e)); var writeListFuture = openedFile.writeList(data, 0, data.length); - writeListFuture.handleException((e) { - checkWriteReadOnlyFileException(e); + writeListFuture.catchError((e) { + checkWriteReadOnlyFileException(e.error); openedFile.close().then((ignore) => port.send(null)); - return true; }); }); } @@ -346,11 +335,10 @@ testTruncateReadOnlyFile() { (e) => checkWriteReadOnlyFileException(e)); var truncateFuture = openedFile.truncate(0); - truncateFuture.then((ignore) => Expect.fail("Unreachable code")); - truncateFuture.handleException((e) { - checkWriteReadOnlyFileException(e); + truncateFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError((e) { + checkWriteReadOnlyFileException(e.error); openedFile.close().then((ignore) => port.send(null)); - return true; }); }); } @@ -392,54 +380,53 @@ testOperateOnClosedFile() { var errorCount = 0; _errorHandler(e) { - checkFileClosedException(e); + checkFileClosedException(e.error); if (--errorCount == 0) { port.send(null); } - return true; } var readByteFuture = openedFile.readByte(); - readByteFuture.then((byte) => Expect.fail("Unreachable code")); - readByteFuture.handleException(_errorHandler); + readByteFuture.then((byte) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var writeByteFuture = openedFile.writeByte(0); - writeByteFuture.then((ignore) => Expect.fail("Unreachable code")); - writeByteFuture.handleException(_errorHandler); + writeByteFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var readListFuture = openedFile.readList(data, 0, data.length); - readListFuture.then((bytesRead) => Expect.fail("Unreachable code")); - readListFuture.handleException(_errorHandler); + readListFuture.then((bytesRead) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var writeListFuture = openedFile.writeList(data, 0, data.length); - writeListFuture.then((ignore) => Expect.fail("Unreachable code")); - writeListFuture.handleException(_errorHandler); + writeListFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var writeStringFuture = openedFile.writeString("Hello"); - writeStringFuture.then((ignore) => Expect.fail("Unreachable code")); - writeStringFuture.handleException(_errorHandler); + writeStringFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var positionFuture = openedFile.position(); - positionFuture.then((position) => Expect.fail("Unreachable code")); - positionFuture.handleException(_errorHandler); + positionFuture.then((position) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var setPositionFuture = openedFile.setPosition(0); - setPositionFuture.then((ignore) => Expect.fail("Unreachable code")); - setPositionFuture.handleException(_errorHandler); + setPositionFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var truncateFuture = openedFile.truncate(0); - truncateFuture.then((ignore) => Expect.fail("Unreachable code")); - truncateFuture.handleException(_errorHandler); + truncateFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var lenFuture = openedFile.length(); - lenFuture.then((length) => Expect.fail("Unreachable code")); - lenFuture.handleException(_errorHandler); + lenFuture.then((length) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; var flushFuture = openedFile.flush(); - flushFuture.then((ignore) => Expect.fail("Unreachable code")); - flushFuture.handleException(_errorHandler); + flushFuture.then((ignore) => Expect.fail("Unreachable code")) + .catchError(_errorHandler); errorCount++; - }); +}); } testRepeatedlyCloseFile() { @@ -447,12 +434,11 @@ testRepeatedlyCloseFile() { var openedFile = file.openSync(); openedFile.close().then((ignore) { var closeFuture = openedFile.close(); - closeFuture.handleException((e) { - Expect.isTrue(e is FileIOException); + closeFuture.then((ignore) => null) + .catchError((e) { + Expect.isTrue(e.error is FileIOException); port.send(null); - return true; }); - closeFuture.then((ignore) => null); }); }); } diff --git a/tests/standalone/io/file_fuzz_test.dart b/tests/standalone/io/file_fuzz_test.dart index 313575ea6e5..873f03785a1 100644 --- a/tests/standalone/io/file_fuzz_test.dart +++ b/tests/standalone/io/file_fuzz_test.dart @@ -5,10 +5,11 @@ // 'fuzz' test the file APIs by providing unexpected type arguments. The test // passes if the VM does not crash. -import "dart:io"; -import "dart:isolate"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; -import "fuzz_support.dart"; +import 'fuzz_support.dart'; fuzzSyncMethods() { typeMapping.forEach((k, v) { diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart index 70834fddc90..c46bd421d41 100644 --- a/tests/standalone/io/file_input_stream_test.dart +++ b/tests/standalone/io/file_input_stream_test.dart @@ -97,7 +97,7 @@ void testUnreadyInputStream() { String fileName = getFilename("tests/standalone/io/readuntil_test.dat"); var expected = "Hello Dart\nwassup!\n".charCodes; InputStream x = (new File(fileName)).openInputStream(); - List buffer = new List(100); + List buffer = new List.fixedLength(100); x.onData = () { Expect.fail("Input stream closed before opening called onData handler."); diff --git a/tests/standalone/io/file_invalid_arguments_test.dart b/tests/standalone/io/file_invalid_arguments_test.dart index f335ac60fd8..f8196e6d4d4 100644 --- a/tests/standalone/io/file_invalid_arguments_test.dart +++ b/tests/standalone/io/file_invalid_arguments_test.dart @@ -18,17 +18,15 @@ class FileTest { var errors = 0; var readListFuture = file.readList(buffer, offset, length); - readListFuture.handleException((e) { + readListFuture.then((bytes) { + Expect.fail('read list invalid arguments'); + }).catchError((e) { errors++; - Expect.isTrue(e is FileIOException); - Expect.isTrue(e.toString().contains('Invalid arguments')); + Expect.isTrue(e.error is FileIOException); + Expect.isTrue(e.error.toString().contains('Invalid arguments')); file.close().then((ignore) { Expect.equals(1, errors); }); - return true; - }); - readListFuture.then((bytes) { - Expect.fail('read list invalid arguments'); }); } @@ -46,12 +44,10 @@ class FileTest { var writeByteFuture = file.writeByte(value); writeByteFuture.then((ignore) { Expect.fail('write byte invalid argument'); - }); - writeByteFuture.handleException((s) { - Expect.isTrue(s is FileIOException); - Expect.isTrue(s.toString().contains('Invalid argument')); + }).catchError((s) { + Expect.isTrue(s.error is FileIOException); + Expect.isTrue(s.error.toString().contains('Invalid argument')); file.close(); - return true; }); } @@ -69,12 +65,10 @@ class FileTest { var writeListFuture = file.writeList(buffer, offset, bytes); writeListFuture.then((ignore) { Expect.fail('write list invalid argument'); - }); - writeListFuture.handleException((s) { - Expect.isTrue(s is FileIOException); - Expect.isTrue(s.toString().contains('Invalid arguments')); + }).catchError((s) { + Expect.isTrue(s.error is FileIOException); + Expect.isTrue(s.error.toString().contains('Invalid arguments')); file.close(); - return true; }); } @@ -112,10 +106,10 @@ class FileTest { main() { FileTest.testReadListInvalidArgs(12, 0, 1); - FileTest.testReadListInvalidArgs(new List(10), '0', 1); - FileTest.testReadListInvalidArgs(new List(10), 0, '1'); + FileTest.testReadListInvalidArgs(new List.fixedLength(10), '0', 1); + FileTest.testReadListInvalidArgs(new List.fixedLength(10), 0, '1'); FileTest.testWriteByteInvalidArgs('asdf'); FileTest.testWriteListInvalidArgs(12, 0, 1); - FileTest.testWriteListInvalidArgs(new List(10), '0', 1); - FileTest.testWriteListInvalidArgs(new List(10), 0, '1'); + FileTest.testWriteListInvalidArgs(new List.fixedLength(10), '0', 1); + FileTest.testWriteListInvalidArgs(new List.fixedLength(10), 0, '1'); } diff --git a/tests/standalone/io/file_non_ascii_test.dart b/tests/standalone/io/file_non_ascii_test.dart index da136e605bb..98b8336a685 100644 --- a/tests/standalone/io/file_non_ascii_test.dart +++ b/tests/standalone/io/file_non_ascii_test.dart @@ -48,5 +48,8 @@ main() { }); }); }); + }).catchError((e) { + port.close(); + Expect.fail("File not found"); }); } diff --git a/tests/standalone/io/file_output_stream_test.dart b/tests/standalone/io/file_output_stream_test.dart index 88b314cb1fd..e700c5c645f 100644 --- a/tests/standalone/io/file_output_stream_test.dart +++ b/tests/standalone/io/file_output_stream_test.dart @@ -55,7 +55,7 @@ void testOutputStreamNoPendingWrite() { stream.close(); } stream.onClosed = () { - List buffer = new List(total); + List buffer = new List.fixedLength(total); File fileSync = new File(fileName); var openedFile = fileSync.openSync(); openedFile.readListSync(buffer, 0, total); diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart index 26ec50a6b96..93dccf48c57 100644 --- a/tests/standalone/io/file_test.dart +++ b/tests/standalone/io/file_test.dart @@ -4,8 +4,9 @@ // // Dart test program for testing file I/O. -import "dart:io"; -import "dart:isolate"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; class MyListOfOneElement implements List { int _value; @@ -47,7 +48,7 @@ class FileTest { Expect.isTrue('$file'.contains(file.name)); InputStream input = file.openInputStream(); input.onData = () { - List buffer = new List(42); + List buffer = new List.fixedLength(42); int bytesRead = input.readInto(buffer, 0, 12); Expect.equals(12, bytesRead); bytesRead = input.readInto(buffer, 12, 30); @@ -83,7 +84,7 @@ class FileTest { var input1 = file1.openInputStream(); List buffer1; input1.onData = () { - buffer1 = new List(42); + buffer1 = new List.fixedLength(42); bytesRead = input1.readInto(buffer1, 0, 42); Expect.equals(42, bytesRead); }; @@ -139,7 +140,7 @@ class FileTest { output.close(); output.onClosed = () { // Now read the contents of the file just written. - List buffer2 = new List(42); + List buffer2 = new List.fixedLength(42); var file6 = new File(outFilename); var input6 = file6.openInputStream(); input6.onData = () { @@ -170,7 +171,7 @@ class FileTest { asyncTestStarted(); // Create the test data - arbitrary binary data. - List buffer = new List(100000); + List buffer = new List.fixedLength(100000); for (var i = 0; i < buffer.length; ++i) { buffer[i] = i % 256; } @@ -202,7 +203,8 @@ class FileTest { asyncTestDone('testReadWriteStreamLargeFile: length check'); }); - List inputBuffer = new List(expectedLength + 100000); + List inputBuffer = + new List.fixedLength(expectedLength + 100000); // Immediate read should read 0 bytes. Expect.equals(0, input.available()); Expect.equals(false, input.closed); @@ -241,14 +243,12 @@ class FileTest { Future testPipeDone = testPipe(file, buffer); - Future futureDeleted = testPipeDone.chain((ignored) => file.delete()); - futureDeleted.handleException((e) { - print('Exception while deleting ReadWriteStreamLargeFile file'); - print('Exception $e'); - return false; // Throw exception further. - }); + Future futureDeleted = testPipeDone.then((ignored) => file.delete()); futureDeleted.then((ignored) { asyncTestDone('testReadWriteStreamLargeFile: main test'); + }).catchError((e) { + print('Exception while deleting ReadWriteStreamLargeFile file'); + print('Exception $e'); }); }; // Try a read again after handlers are set. @@ -292,7 +292,7 @@ class FileTest { String filename = getFilename("bin/file_test.cc"); File file = new File(filename); file.open(FileMode.READ).then((RandomAccessFile file) { - List buffer = new List(10); + List buffer = new List.fixedLength(10); file.readList(buffer, 0, 5).then((bytes_read) { Expect.equals(5, bytes_read); file.readList(buffer, 5, 5).then((bytes_read) { @@ -317,7 +317,7 @@ class FileTest { // Read a file and check part of it's contents. String filename = getFilename("bin/file_test.cc"); RandomAccessFile file = (new File(filename)).openSync(); - List buffer = new List(42); + List buffer = new List.fixedLength(42); int bytes_read = 0; bytes_read = file.readListSync(buffer, 0, 12); Expect.equals(12, bytes_read); @@ -343,7 +343,7 @@ class FileTest { String inFilename = getFilename("tests/vm/data/fixed_length_file"); final File file = new File(inFilename); file.open(FileMode.READ).then((openedFile) { - List buffer1 = new List(42); + List buffer1 = new List.fixedLength(42); openedFile.readList(buffer1, 0, 42).then((bytes_read) { Expect.equals(42, bytes_read); openedFile.close().then((ignore) { @@ -359,7 +359,7 @@ class FileTest { file2.open(FileMode.WRITE).then((openedFile2) { openedFile2.writeList(buffer1, 0, bytes_read).then((ignore) { openedFile2.close().then((ignore) { - List buffer2 = new List(bytes_read); + List buffer2 = new List.fixedLength(bytes_read); final File file3 = new File(outFilename); file3.open(FileMode.READ).then((openedFile3) { openedFile3.readList(buffer2, 0, 42).then((bytes_read) { @@ -484,7 +484,7 @@ class FileTest { // Read a file. String inFilename = getFilename("tests/vm/data/fixed_length_file"); RandomAccessFile file = (new File(inFilename)).openSync(); - List buffer1 = new List(42); + List buffer1 = new List.fixedLength(42); int bytes_read = 0; int bytes_written = 0; bytes_read = file.readListSync(buffer1, 0, 42); @@ -503,7 +503,7 @@ class FileTest { openedFile.writeListSync(buffer1, 0, bytes_read); openedFile.closeSync(); // Now read the contents of the file just written. - List buffer2 = new List(bytes_read); + List buffer2 = new List.fixedLength(bytes_read); openedFile = (new File(outFilename)).openSync(); bytes_read = openedFile.readListSync(buffer2, 0, 42); Expect.equals(42, bytes_read); @@ -571,7 +571,7 @@ class FileTest { var openedFile2 = file2.openSync(); var length = openedFile2.lengthSync(); Expect.equals(8, length); - List data = new List(length); + List data = new List.fixedLength(length); openedFile2.readListSync(data, 0, length); for (var i = 0; i < data.length; i++) { Expect.equals(i, data[i]); @@ -600,8 +600,8 @@ class FileTest { var file = new File("${tempDir}/testDirectory"); var errors = 0; var dirFuture = file.directory(); - dirFuture.then((d) => Expect.fail("non-existing file")); - dirFuture.handleException((e) { + dirFuture.then((d) => Expect.fail("non-existing file")) + .catchError((e) { file.create().then((ignore) { file.directory().then((Directory d) { d.exists().then((exists) { @@ -610,22 +610,19 @@ class FileTest { file.delete().then((ignore) { var fileDir = new File("."); var dirFuture2 = fileDir.directory(); - dirFuture2.then((d) => Expect.fail("non-existing file")); - dirFuture2.handleException((e) { + dirFuture2.then((d) => Expect.fail("non-existing file")) + .catchError((e) { var fileDir = new File(tempDir); var dirFuture3 = fileDir.directory(); - dirFuture3.then((d) => Expect.fail("non-existing file")); - dirFuture3.handleException((e) { + dirFuture3.then((d) => Expect.fail("non-existing file")) + .catchError((e) { port.toSendPort().send(1); - return true; }); - return true; }); }); }); }); }); - return true; }); } @@ -678,7 +675,7 @@ class FileTest { RandomAccessFile input = (new File(filename)).openSync(); input.position().then((position) { Expect.equals(0, position); - List buffer = new List(100); + List buffer = new List.fixedLength(100); input.readList(buffer, 0, 12).then((bytes_read) { input.position().then((position) { Expect.equals(12, position); @@ -702,7 +699,7 @@ class FileTest { String filename = getFilename("tests/vm/data/fixed_length_file"); RandomAccessFile input = (new File(filename)).openSync(); Expect.equals(0, input.positionSync()); - List buffer = new List(100); + List buffer = new List.fixedLength(100); input.readListSync(buffer, 0, 12); Expect.equals(12, input.positionSync()); input.readListSync(buffer, 12, 6); @@ -789,7 +786,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(100); + List buffer = new List.fixedLength(100); openedFile.readListSync(buffer, 0, 10); } on FileIOException catch (ex) { exceptionCaught = true; @@ -800,7 +797,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(100); + List buffer = new List.fixedLength(100); openedFile.writeListSync(buffer, 0, 10); } on FileIOException catch (ex) { exceptionCaught = true; @@ -845,7 +842,7 @@ class FileTest { // Tests stream exception handling after file was closed. static void testCloseExceptionStream() { asyncTestStarted(); - List buffer = new List(42); + List buffer = new List.fixedLength(42); File file = new File(tempDirectory.path.concat("/out_close_exception_stream")); file.createSync(); @@ -871,7 +868,7 @@ class FileTest { new File(tempDirectory.path.concat("/out_buffer_out_of_bounds")); RandomAccessFile openedFile = file.openSync(FileMode.WRITE); try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.readListSync(buffer, 0, 12); } on RangeError catch (ex) { exceptionCaught = true; @@ -882,7 +879,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.readListSync(buffer, 6, 6); } on RangeError catch (ex) { exceptionCaught = true; @@ -893,7 +890,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.readListSync(buffer, -1, 1); } on RangeError catch (ex) { exceptionCaught = true; @@ -904,7 +901,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.readListSync(buffer, 0, -1); } on RangeError catch (ex) { exceptionCaught = true; @@ -915,7 +912,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.writeListSync(buffer, 0, 12); } on RangeError catch (ex) { exceptionCaught = true; @@ -926,7 +923,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.writeListSync(buffer, 6, 6); } on RangeError catch (ex) { exceptionCaught = true; @@ -937,7 +934,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.writeListSync(buffer, -1, 1); } on RangeError catch (ex) { exceptionCaught = true; @@ -948,7 +945,7 @@ class FileTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); openedFile.writeListSync(buffer, 0, -1); } on RangeError catch (ex) { exceptionCaught = true; @@ -964,8 +961,8 @@ class FileTest { static void testOpenDirectoryAsFile() { var f = new File('.'); var future = f.open(FileMode.READ); - future.then((r) => Expect.fail('Directory opened as file')); - future.handleException((e) => true); + future.then((r) => Expect.fail('Directory opened as file')) + .catchError((e) {}); } static void testOpenDirectoryAsFileSync() { @@ -1054,10 +1051,8 @@ class FileTest { var readAsStringFuture = f.readAsString(Encoding.ASCII); readAsStringFuture.then((text) { Expect.fail("Non-ascii char should cause error"); - }); - readAsStringFuture.handleException((e) { + }).catchError((e) { port.toSendPort().send(1); - return true; }); }); }); @@ -1141,20 +1136,17 @@ class FileTest { Expect.throws(f.readAsStringSync, (e) => e is FileIOException); Expect.throws(f.readAsLinesSync, (e) => e is FileIOException); var readAsBytesFuture = f.readAsBytes(); - readAsBytesFuture.then((bytes) => Expect.fail("no bytes expected")); - readAsBytesFuture.handleException((e) { + readAsBytesFuture.then((bytes) => Expect.fail("no bytes expected")) + .catchError((e) { var readAsStringFuture = f.readAsString(Encoding.UTF_8); - readAsStringFuture.then((text) => Expect.fail("no text expected")); - readAsStringFuture.handleException((e) { + readAsStringFuture.then((text) => Expect.fail("no text expected")) + .catchError((e) { var readAsLinesFuture = f.readAsLines(Encoding.UTF_8); - readAsLinesFuture.then((lines) => Expect.fail("no lines expected")); - readAsLinesFuture.handleException((e) { + readAsLinesFuture.then((lines) => Expect.fail("no lines expected")) + .catchError((e) { port.toSendPort().send(1); - return true; }); - return true; }); - return true; }); } diff --git a/tests/standalone/io/file_write_as_test.dart b/tests/standalone/io/file_write_as_test.dart index 466c06bb65e..fd53f07455c 100644 --- a/tests/standalone/io/file_write_as_test.dart +++ b/tests/standalone/io/file_write_as_test.dart @@ -2,6 +2,7 @@ // 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. +import 'dart:async'; import 'dart:io'; import 'dart:isolate'; @@ -70,7 +71,7 @@ main() { var tempDir = new Directory('').createTempSync(); testWriteAsBytesSync(tempDir); testWriteAsStringSync(tempDir); - testWriteAsBytes(tempDir).chain((_) { + testWriteAsBytes(tempDir).then((_) { return testWriteAsString(tempDir); }).then((_) { tempDir.deleteSync(recursive: true); diff --git a/tests/standalone/io/fuzz_support.dart b/tests/standalone/io/fuzz_support.dart index 64f96a75b5d..4c7cd1cd399 100644 --- a/tests/standalone/io/fuzz_support.dart +++ b/tests/standalone/io/fuzz_support.dart @@ -4,7 +4,8 @@ library fuzz_support; -import "dart:io"; +import 'dart:async'; +import 'dart:io'; const typeMapping = const { 'null': null, @@ -46,14 +47,7 @@ doItSync(Function f) { // Perform async operation and transform the future for the operation // into a future that never fails by treating errors as normal // completion. -Future doItAsync(Function f) { +Future doItAsync(void f()) { // Ignore value and errors. - var completer = new Completer(); - var future = f(); - future.handleException((e) { - completer.complete(true); - return true; - }); - future.then((v) => completer.complete(true)); - return completer.future; + return new Future.delayed(0, f).catchError((_) {}).then((_) => true); } diff --git a/tests/standalone/io/http_advanced_test.dart b/tests/standalone/io/http_advanced_test.dart index c08916b3744..cb8245ff62a 100644 --- a/tests/standalone/io/http_advanced_test.dart +++ b/tests/standalone/io/http_advanced_test.dart @@ -7,8 +7,9 @@ // VMOptions=--short_socket_write // VMOptions=--short_socket_read --short_socket_write -import "dart:isolate"; -import "dart:io"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; class TestServerMain { TestServerMain() @@ -465,13 +466,13 @@ Future testFlush() { void main() { print('testHost()'); - testHost().chain((_) { + testHost().then((_) { print('testExpires()'); - return testExpires().chain((_) { + return testExpires().then((_) { print('testContentType()'); - return testContentType().chain((_) { + return testContentType().then((_) { print('testCookies()'); - return testCookies().chain((_) { + return testCookies().then((_) { print('testFlush()'); return testFlush(); }); diff --git a/tests/standalone/io/http_auth_test.dart b/tests/standalone/io/http_auth_test.dart index 7272658f059..94c7b3befdd 100644 --- a/tests/standalone/io/http_auth_test.dart +++ b/tests/standalone/io/http_auth_test.dart @@ -2,11 +2,12 @@ // 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. -import "dart:isolate"; -import "dart:crypto"; -import "dart:io"; -import "dart:uri"; -import "dart:utf"; +import 'dart:async'; +import 'dart:crypto'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:uri'; +import 'dart:utf'; class Server { HttpServer server; diff --git a/tests/standalone/io/http_connection_close_test.dart b/tests/standalone/io/http_connection_close_test.dart index 1e1022323f8..b6116d25981 100644 --- a/tests/standalone/io/http_connection_close_test.dart +++ b/tests/standalone/io/http_connection_close_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. // -import "dart:isolate"; +import "dart:async"; import "dart:io"; import "dart:uri"; @@ -13,7 +13,7 @@ void testHttp10Close(bool closeRequest) { Socket socket = new Socket("127.0.0.1", server.port); socket.onConnect = () { - List buffer = new List(1024); + List buffer = new List.fixedLength(1024); socket.outputStream.writeString("GET / HTTP/1.0\r\n\r\n"); if (closeRequest) socket.outputStream.close(); socket.onData = () => socket.readList(buffer, 0, buffer.length); @@ -30,7 +30,7 @@ void testHttp11Close(bool closeRequest) { Socket socket = new Socket("127.0.0.1", server.port); socket.onConnect = () { - List buffer = new List(1024); + List buffer = new List.fixedLength(1024); socket.outputStream.writeString( "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"); if (closeRequest) socket.outputStream.close(); diff --git a/tests/standalone/io/http_connection_header_test.dart b/tests/standalone/io/http_connection_header_test.dart index 03c7d93403d..77cf97671ee 100644 --- a/tests/standalone/io/http_connection_header_test.dart +++ b/tests/standalone/io/http_connection_header_test.dart @@ -17,15 +17,15 @@ void checkExpectedConnectionHeaders(HttpHeaders headers, bool persistentConnection) { Expect.equals("some-value1", headers.value("My-Connection-Header1")); Expect.equals("some-value2", headers.value("My-Connection-Header2")); - Expect.isTrue(headers[HttpHeaders.CONNECTION].some( + Expect.isTrue(headers[HttpHeaders.CONNECTION].any( (value) => value.toLowerCase() == "my-connection-header1")); - Expect.isTrue(headers[HttpHeaders.CONNECTION].some( + Expect.isTrue(headers[HttpHeaders.CONNECTION].any( (value) => value.toLowerCase() == "my-connection-header2")); if (persistentConnection) { Expect.equals(2, headers[HttpHeaders.CONNECTION].length); } else { Expect.equals(3, headers[HttpHeaders.CONNECTION].length); - Expect.isTrue(headers[HttpHeaders.CONNECTION].some( + Expect.isTrue(headers[HttpHeaders.CONNECTION].any( (value) => value.toLowerCase() == "close")); } } diff --git a/tests/standalone/io/http_content_length_test.dart b/tests/standalone/io/http_content_length_test.dart index 8cfe93441a4..62902181737 100644 --- a/tests/standalone/io/http_content_length_test.dart +++ b/tests/standalone/io/http_content_length_test.dart @@ -184,7 +184,7 @@ void testHttp10() { Socket socket = new Socket("127.0.0.1", server.port); socket.onConnect = () { - List buffer = new List(1024); + List buffer = new List.fixedLength(1024); socket.outputStream.writeString("GET / HTTP/1.0\r\n\r\n"); socket.onData = () => socket.readList(buffer, 0, buffer.length); socket.onClosed = () { diff --git a/tests/standalone/io/http_date_test.dart b/tests/standalone/io/http_date_test.dart index 1f4c685f46e..d4bc05851fd 100644 --- a/tests/standalone/io/http_date_test.dart +++ b/tests/standalone/io/http_date_test.dart @@ -2,6 +2,7 @@ // 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. +import "dart:async"; import "dart:math"; part "../../../sdk/lib/io/input_stream.dart"; diff --git a/tests/standalone/io/http_head_test.dart b/tests/standalone/io/http_head_test.dart index a1f91ec8d49..7880e2d3278 100644 --- a/tests/standalone/io/http_head_test.dart +++ b/tests/standalone/io/http_head_test.dart @@ -18,7 +18,7 @@ void testHEAD(int totalConnections) { (request) => request.path == "/test200", (HttpRequest request, HttpResponse response) { response.contentLength = 200; - List data = new List(200); + List data = new List.fixedLength(200); response.outputStream.write(data); response.outputStream.close(); }); diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart index 9676fed42dc..444b0fd8355 100644 --- a/tests/standalone/io/http_headers_test.dart +++ b/tests/standalone/io/http_headers_test.dart @@ -2,6 +2,7 @@ // 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. +import 'dart:async'; import 'dart:math'; part "../../../sdk/lib/io/input_stream.dart"; diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart index dafd9f9d34e..fe4018a91bf 100644 --- a/tests/standalone/io/http_parser_test.dart +++ b/tests/standalone/io/http_parser_test.dart @@ -2,6 +2,7 @@ // 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. +import 'dart:async'; import 'dart:math'; import 'dart:scalarlist'; diff --git a/tests/standalone/io/http_read_test.dart b/tests/standalone/io/http_read_test.dart index 3a62e6a47b1..bb8a87a4f39 100644 --- a/tests/standalone/io/http_read_test.dart +++ b/tests/standalone/io/http_read_test.dart @@ -182,7 +182,7 @@ void testReadInto(bool chunkedEncoding) { InputStream stream = response.inputStream; List body = new List(); stream.onData = () { - List tmp = new List(3); + List tmp = new List.fixedLength(3); int bytes = stream.readInto(tmp); body.addAll(tmp.getRange(0, bytes)); }; diff --git a/tests/standalone/io/http_server_early_client_close_test.dart b/tests/standalone/io/http_server_early_client_close_test.dart index d4d009c2f4e..a6b19ce21ac 100644 --- a/tests/standalone/io/http_server_early_client_close_test.dart +++ b/tests/standalone/io/http_server_early_client_close_test.dart @@ -2,6 +2,7 @@ // 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. +import "dart:async"; import "dart:io"; import "dart:isolate"; @@ -85,13 +86,13 @@ void testEarlyClose() { HttpServer server = new HttpServer(); server.listen("127.0.0.1", 0); void runTest(Iterator it) { - if (it.hasNext) { - it.next().execute(server).then((_) => runTest(it)); + if (it.moveNext()) { + it.current.execute(server).then((_) => runTest(it)); } else { server.close(); } } - runTest(tests.iterator()); + runTest(tests.iterator); } void main() { diff --git a/tests/standalone/io/http_server_early_server_close_test.dart b/tests/standalone/io/http_server_early_server_close_test.dart index f7f986139fc..8819ef22c99 100644 --- a/tests/standalone/io/http_server_early_server_close_test.dart +++ b/tests/standalone/io/http_server_early_server_close_test.dart @@ -2,6 +2,7 @@ // 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. +import "dart:async"; import "dart:io"; import "dart:isolate"; diff --git a/tests/standalone/io/http_session_test.dart b/tests/standalone/io/http_session_test.dart index 51580097379..0b83bf4fb59 100644 --- a/tests/standalone/io/http_session_test.dart +++ b/tests/standalone/io/http_session_test.dart @@ -2,7 +2,8 @@ // 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. -import "dart:io"; +import 'dart:async'; +import 'dart:io'; const SESSION_ID = "DARTSESSID"; @@ -50,10 +51,10 @@ void testSessions(int sessionCount) { var futures = []; for (int i = 0; i < sessionCount; i++) { - futures.add(connectGetSession(server.port).chain((session) { + futures.add(connectGetSession(server.port).then((session) { Expect.isNotNull(session); Expect.isTrue(sessions.contains(session)); - return connectGetSession(server.port, session).transform((session2) { + return connectGetSession(server.port, session).then((session2) { Expect.equals(session2, session); Expect.isTrue(sessions.contains(session2)); return session2; @@ -89,7 +90,7 @@ void testTimeout(int sessionCount) { Futures.wait(timeouts).then((_) { futures = []; for (var id in clientSessions) { - futures.add(connectGetSession(server.port, id).transform((session) { + futures.add(connectGetSession(server.port, id).then((session) { Expect.isNotNull(session); Expect.notEquals(id, session); })); diff --git a/tests/standalone/io/http_shutdown_test.dart b/tests/standalone/io/http_shutdown_test.dart index 077eb83b133..6d83bd437ae 100644 --- a/tests/standalone/io/http_shutdown_test.dart +++ b/tests/standalone/io/http_shutdown_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. // -import "dart:isolate"; +import "dart:async"; import "dart:io"; void test1(int totalConnections) { diff --git a/tests/standalone/io/https_client_certificate_test.dart b/tests/standalone/io/https_client_certificate_test.dart index 572b30fc92b..029c8fd2f38 100644 --- a/tests/standalone/io/https_client_certificate_test.dart +++ b/tests/standalone/io/https_client_certificate_test.dart @@ -2,6 +2,7 @@ // 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. +import "dart:async"; import "dart:io"; import "dart:uri"; import "dart:isolate"; @@ -64,7 +65,7 @@ Function test(Map options) { return completer.future; } - testConnect(true).chain(testConnect).then((_) { + testConnect(true).then(testConnect).then((_) { client.shutdown(); server.close(); Expect.throws(() => server.port); @@ -88,7 +89,7 @@ void main() { InitializeSSL(); // Test two connections in sequence. test({'certificateName': null})() - .chain(test({'certificateName': 'localhost_cert'})) + .then(test({'certificateName': 'localhost_cert'})) .then((_) { Expect.equals(2, numClientCertificatesReceived); keepAlive.close(); diff --git a/tests/standalone/io/list_input_stream_test.dart b/tests/standalone/io/list_input_stream_test.dart index 6826f1b705f..cebf50d9f9d 100644 --- a/tests/standalone/io/list_input_stream_test.dart +++ b/tests/standalone/io/list_input_stream_test.dart @@ -78,7 +78,7 @@ void testListInputStream2() { ReceivePort donePort = new ReceivePort(); void onData() { - List x = new List(2); + List x = new List.fixedLength(2); var bytesRead = stream.readInto(x); Expect.equals(2, bytesRead); Expect.equals(data[count++], x[0]); diff --git a/tests/standalone/io/list_output_stream_test.dart b/tests/standalone/io/list_output_stream_test.dart index a9a5b258ae1..6be222af48b 100644 --- a/tests/standalone/io/list_output_stream_test.dart +++ b/tests/standalone/io/list_output_stream_test.dart @@ -2,8 +2,9 @@ // 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. -import "dart:io"; -import "dart:isolate"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; void testEmptyListOutputStream1() { ListOutputStream stream = new ListOutputStream(); diff --git a/tests/standalone/io/options_test.dart b/tests/standalone/io/options_test.dart index 0c93f0381be..d326ab4a526 100644 --- a/tests/standalone/io/options_test.dart +++ b/tests/standalone/io/options_test.dart @@ -11,9 +11,9 @@ main() { // Basic test for functionality. Expect.equals(3, opts.arguments.length); - Expect.equals(10, parseInt(opts.arguments[0])); + Expect.equals(10, int.parse(opts.arguments[0])); Expect.equals("options_test", opts.arguments[1]); - Expect.equals(20, parseInt(opts.arguments[2])); + Expect.equals(20, int.parse(opts.arguments[2])); Expect.isTrue(opts.executable.contains('dart')); Expect.isTrue(opts.script.replaceAll('\\', '/'). endsWith('tests/standalone/io/options_test.dart')); @@ -21,15 +21,15 @@ main() { // Now add an additional argument. opts.arguments.add("Fourth"); Expect.equals(4, opts.arguments.length); - Expect.equals(10, parseInt(opts.arguments[0])); + Expect.equals(10, int.parse(opts.arguments[0])); Expect.equals("options_test", opts.arguments[1]); - Expect.equals(20, parseInt(opts.arguments[2])); + Expect.equals(20, int.parse(opts.arguments[2])); Expect.equals("Fourth", opts.arguments[3]); // Check that a new options object still gets the original arguments. var opts2 = new Options(); Expect.equals(3, opts2.arguments.length); - Expect.equals(10, parseInt(opts2.arguments[0])); + Expect.equals(10, int.parse(opts2.arguments[0])); Expect.equals("options_test", opts2.arguments[1]); - Expect.equals(20, parseInt(opts2.arguments[2])); + Expect.equals(20, int.parse(opts2.arguments[2])); } diff --git a/tests/standalone/io/process_check_arguments_script.dart b/tests/standalone/io/process_check_arguments_script.dart index 8a70edaf1f3..6e9c086efc3 100644 --- a/tests/standalone/io/process_check_arguments_script.dart +++ b/tests/standalone/io/process_check_arguments_script.dart @@ -9,8 +9,8 @@ import "dart:math"; main() { var options = new Options(); Expect.isTrue(options.script.endsWith('process_check_arguments_script.dart')); - var expected_num_args = parseInt(options.arguments[0]); - var contains_quote = parseInt(options.arguments[1]); + var expected_num_args = int.parse(options.arguments[0]); + var contains_quote = int.parse(options.arguments[1]); Expect.equals(expected_num_args, options.arguments.length); for (var i = 2; i < options.arguments.length; i++) { Expect.isTrue((contains_quote == 0) || options.arguments[i].contains('"')); diff --git a/tests/standalone/io/process_start_exception_test.dart b/tests/standalone/io/process_start_exception_test.dart index 4a6d319a9a1..a75b131bfbb 100644 --- a/tests/standalone/io/process_start_exception_test.dart +++ b/tests/standalone/io/process_start_exception_test.dart @@ -4,17 +4,17 @@ // // Process test program to errors during startup of the process. -import "dart:io"; +import 'dart:async'; +import 'dart:io'; testStartError() { Future processFuture = Process.start("__path_to_something_that_should_not_exist__", const []); - processFuture.then((p) => Expect.fail('got process despite start error')); - processFuture.handleException((e) { - Expect.isTrue(e is ProcessException); - Expect.equals(2, e.errorCode, e.toString()); - return true; + processFuture.then((p) => Expect.fail('got process despite start error')) + .catchError((e) { + Expect.isTrue(e.error is ProcessException); + Expect.equals(2, e.error.errorCode, e.error.toString()); }); } @@ -23,12 +23,10 @@ testRunError() { Process.run("__path_to_something_that_should_not_exist__", const []); - processFuture.then((result) => Expect.fail("exit handler called")); - - processFuture.handleException((e) { - Expect.isTrue(e is ProcessException); - Expect.equals(2, e.errorCode, e.toString()); - return true; + processFuture.then((result) => Expect.fail("exit handler called")) + .catchError((e) { + Expect.isTrue(e.error is ProcessException); + Expect.equals(2, e.error.errorCode, e.error.toString()); }); } diff --git a/tests/standalone/io/process_stderr_test.dart b/tests/standalone/io/process_stderr_test.dart index 53f93588ec7..b84d81c73d0 100644 --- a/tests/standalone/io/process_stderr_test.dart +++ b/tests/standalone/io/process_stderr_test.dart @@ -9,8 +9,9 @@ // VMOptions=--short_socket_write // VMOptions=--short_socket_read --short_socket_write -import "dart:io"; -import "dart:math"; +import 'dart:async'; +import 'dart:io'; +import 'dart:math'; import "process_test_util.dart"; diff --git a/tests/standalone/io/process_stdout_test.dart b/tests/standalone/io/process_stdout_test.dart index ddf80371ad5..200faf0ca4f 100644 --- a/tests/standalone/io/process_stdout_test.dart +++ b/tests/standalone/io/process_stdout_test.dart @@ -9,8 +9,9 @@ // VMOptions=--short_socket_write // VMOptions=--short_socket_read --short_socket_write -import "dart:io"; -import "dart:math"; +import 'dart:async'; +import 'dart:io'; +import 'dart:math'; import "process_test_util.dart"; diff --git a/tests/standalone/io/process_working_directory_test.dart b/tests/standalone/io/process_working_directory_test.dart index b5fe0ee88ad..3240cb95ec2 100644 --- a/tests/standalone/io/process_working_directory_test.dart +++ b/tests/standalone/io/process_working_directory_test.dart @@ -31,8 +31,7 @@ class ProcessWorkingDirectoryTest { }; process.stdout.onData = process.stdout.read; process.stderr.onData = process.stderr.read; - }); - processFuture.handleException((error) { + }).catchError((error) { directory.deleteSync(); Expect.fail("Couldn't start process"); }); @@ -50,12 +49,9 @@ class ProcessWorkingDirectoryTest { future.then((process) { Expect.fail("bad process completed"); directory.deleteSync(); - }); - - future.handleException((e) { + }).catchError((e) { Expect.isNotNull(e); directory.deleteSync(); - return true; }); } } diff --git a/tests/standalone/io/regress_7097_test.dart b/tests/standalone/io/regress_7097_test.dart index 28b0e9f0e8d..ee108223b01 100644 --- a/tests/standalone/io/regress_7097_test.dart +++ b/tests/standalone/io/regress_7097_test.dart @@ -2,6 +2,7 @@ // 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. +import 'dart:async'; import 'dart:io'; import 'dart:uri'; diff --git a/tests/standalone/io/secure_session_resume_test.dart b/tests/standalone/io/secure_session_resume_test.dart index 825351ace31..e9372d67e9f 100644 --- a/tests/standalone/io/secure_session_resume_test.dart +++ b/tests/standalone/io/secure_session_resume_test.dart @@ -11,6 +11,7 @@ // Session resume is currently disabled - see issue // https://code.google.com/p/dart/issues/detail?id=7230 +import "dart:async"; import "dart:io"; import "dart:isolate"; diff --git a/tests/standalone/io/secure_socket_bad_certificate_test.dart b/tests/standalone/io/secure_socket_bad_certificate_test.dart index 2f27d9b6a0d..f6bc1fc4d56 100644 --- a/tests/standalone/io/secure_socket_bad_certificate_test.dart +++ b/tests/standalone/io/secure_socket_bad_certificate_test.dart @@ -8,6 +8,7 @@ // www.google.dk. Add this to the test when we have secure server sockets. // See TODO below. +import "dart:async"; import "dart:isolate"; import "dart:io"; diff --git a/tests/standalone/io/secure_socket_test.dart b/tests/standalone/io/secure_socket_test.dart index b520c22fa1f..e1fe2a8e332 100644 --- a/tests/standalone/io/secure_socket_test.dart +++ b/tests/standalone/io/secure_socket_test.dart @@ -45,7 +45,7 @@ void main() { secure.onData = useReadList; } useReadList = () { - var buffer = new List(2000); + var buffer = new List.fixedLength(2000); int len = secure.readList(buffer, 0, 2000); var received = new String.fromCharCodes(buffer.getRange(0, len)); chunks.add(received); diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart index b74103e4107..044cd222cde 100644 --- a/tests/standalone/io/skipping_dart2js_compilations_test.dart +++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart @@ -14,8 +14,8 @@ * output (+deps file), dart application) */ +import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; import 'dart:uri'; import '../../../tools/testing/dart/test_suite.dart' as suite; import '../../../tools/testing/dart/test_runner.dart' as runner; diff --git a/tests/standalone/io/socket_close_test.dart b/tests/standalone/io/socket_close_test.dart index efb6f20218e..426f45a557c 100644 --- a/tests/standalone/io/socket_close_test.dart +++ b/tests/standalone/io/socket_close_test.dart @@ -9,8 +9,9 @@ // // Test socket close events. -import "dart:io"; -import "dart:isolate"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; const SERVERSHUTDOWN = -1; const ITERATIONS = 10; @@ -51,7 +52,7 @@ class SocketClose { case 4: case 5: case 6: - List b = new List(5); + List b = new List.fixedLength(5); _readBytes += _socket.readList(b, 0, 5); if ((_readBytes % 5) == 0) { _dataEvents++; @@ -219,7 +220,7 @@ class SocketCloseServer { var connection = data.connection; void readBytes(whenFiveBytes) { - List b = new List(5); + List b = new List.fixedLength(5); data.readBytes += connection.readList(b, 0, 5); if (data.readBytes == 5) { whenFiveBytes(); diff --git a/tests/standalone/io/socket_exception_test.dart b/tests/standalone/io/socket_exception_test.dart index 8708a4c0616..fe5399f0e3b 100644 --- a/tests/standalone/io/socket_exception_test.dart +++ b/tests/standalone/io/socket_exception_test.dart @@ -68,7 +68,7 @@ class SocketExceptionTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); client.readList(buffer, 0 , 10); } on SocketIOException catch(ex) { exceptionCaught = true; @@ -79,7 +79,7 @@ class SocketExceptionTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); client.writeList(buffer, 0, 10); } on SocketIOException catch(ex) { exceptionCaught = true; @@ -90,7 +90,7 @@ class SocketExceptionTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(42); + List buffer = new List.fixedLength(42); input.readInto(buffer, 0, 12); } on SocketIOException catch(ex) { exceptionCaught = true; @@ -101,7 +101,7 @@ class SocketExceptionTest { Expect.equals(true, !wrongExceptionCaught); exceptionCaught = false; try { - List buffer = new List(42); + List buffer = new List.fixedLength(42); output.writeFrom(buffer, 0, 12); } on SocketIOException catch(ex) { exceptionCaught = true; @@ -126,7 +126,7 @@ class SocketExceptionTest { client.onConnect = () { Expect.equals(true, client != null); try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); client.readList(buffer, -1, 1); } on RangeError catch (ex) { exceptionCaught = true; @@ -138,7 +138,7 @@ class SocketExceptionTest { exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); client.readList(buffer, 0, -1); } on RangeError catch (ex) { exceptionCaught = true; @@ -150,7 +150,7 @@ class SocketExceptionTest { exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); client.writeList(buffer, -1, 1); } on RangeError catch (ex) { exceptionCaught = true; @@ -162,7 +162,7 @@ class SocketExceptionTest { exceptionCaught = false; try { - List buffer = new List(10); + List buffer = new List.fixedLength(10); client.writeList(buffer, 0, -1); } on RangeError catch (ex) { exceptionCaught = true; diff --git a/tests/standalone/io/socket_many_connections_test.dart b/tests/standalone/io/socket_many_connections_test.dart index 6e718f90c01..3aabf60c6ea 100644 --- a/tests/standalone/io/socket_many_connections_test.dart +++ b/tests/standalone/io/socket_many_connections_test.dart @@ -17,7 +17,7 @@ class SocketManyConnectionsTest { : _receivePort = new ReceivePort(), _sendPort = null, _connections = 0, - _sockets = new List(CONNECTIONS) { + _sockets = new List.fixedLength(CONNECTIONS) { _sendPort = spawnFunction(startTestServer); initialize(); } diff --git a/tests/standalone/io/socket_stream_close_test.dart b/tests/standalone/io/socket_stream_close_test.dart index b6fa345c4d9..f9b634d8d77 100644 --- a/tests/standalone/io/socket_stream_close_test.dart +++ b/tests/standalone/io/socket_stream_close_test.dart @@ -9,8 +9,9 @@ // // Test socket close events. -import "dart:io"; -import "dart:isolate"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; const SERVERSHUTDOWN = -1; const ITERATIONS = 10; diff --git a/tests/standalone/io/stream_pipe_test.dart b/tests/standalone/io/stream_pipe_test.dart index 3468aaec133..8a1b91052bc 100644 --- a/tests/standalone/io/stream_pipe_test.dart +++ b/tests/standalone/io/stream_pipe_test.dart @@ -35,8 +35,8 @@ bool compareFileContent(String fileName1, } } if (count == null) count = length1; - var data1 = new List(count); - var data2 = new List(count); + var data1 = new List.fixedLength(count); + var data2 = new List.fixedLength(count); if (file1Offset != 0) file1.setPositionSync(file1Offset); if (file2Offset != 0) file2.setPositionSync(file2Offset); var read1 = file1.readListSync(data1, 0, count); @@ -223,7 +223,7 @@ testFileToFilePipe2() { dstFileName, count: srcLength)); dst.setPositionSync(srcLength); - var data = new List(1); + var data = new List.fixedLength(1); var read2 = dst.readListSync(data, 0, 1); Expect.equals(32, data[0]); src.closeSync(); diff --git a/tests/standalone/io/test_extension_fail_test.dart b/tests/standalone/io/test_extension_fail_test.dart index ee379bab029..ab63aef2ecb 100644 --- a/tests/standalone/io/test_extension_fail_test.dart +++ b/tests/standalone/io/test_extension_fail_test.dart @@ -44,23 +44,20 @@ void main() { // Copy test_extension shared library, test_extension.dart and // test_extension_fail_tester.dart to the temporary test directory. copyFileToDirectory(getExtensionPath(buildDirectory), - testDirectory).chain((_) { + testDirectory).then((_) { Path extensionDartFile = scriptDirectory.append('test_extension.dart'); return copyFileToDirectory(extensionDartFile, testDirectory); - }).chain((_) { + }).then((_) { Path testExtensionTesterFile = scriptDirectory.append('test_extension_fail_tester.dart'); return copyFileToDirectory(testExtensionTesterFile, testDirectory); - }).chain((_) { + }).then((_) { Path script = testDirectory.append('test_extension_fail_tester.dart'); return Process.run(options.executable, [script.toNativePath()]); - })..then((ProcessResult result) { + }).then((ProcessResult result) { print("ERR: ${result.stderr}\n\n"); print("OUT: ${result.stdout}\n\n"); Expect.equals(255, result.exitCode); Expect.isTrue(result.stderr.contains("Unhandled exception:\nball\n")); - tempDirectory.deleteSync(recursive: true); - })..handleException((_) { - tempDirectory.deleteSync(recursive: true); - }); + }).whenComplete(() => tempDirectory.deleteSync(recursive: true)); } diff --git a/tests/standalone/io/test_extension_fail_tester.dart b/tests/standalone/io/test_extension_fail_tester.dart index 628d8048bb8..b7739cf999e 100644 --- a/tests/standalone/io/test_extension_fail_tester.dart +++ b/tests/standalone/io/test_extension_fail_tester.dart @@ -4,6 +4,7 @@ library test_extension_test; +import "dart:async"; import "dart:isolate"; import "test_extension.dart"; diff --git a/tests/standalone/io/test_extension_test.dart b/tests/standalone/io/test_extension_test.dart index 88b58f76334..619b31d923c 100644 --- a/tests/standalone/io/test_extension_test.dart +++ b/tests/standalone/io/test_extension_test.dart @@ -4,7 +4,9 @@ // // Dart test program for testing native extensions. -import "dart:io"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; Future copyFileToDirectory(Path file, Path directory) { String src = file.toNativePath(); @@ -44,20 +46,20 @@ void main() { // Copy test_extension shared library, test_extension.dart and // test_extension_tester.dart to the temporary test directory. copyFileToDirectory(getExtensionPath(buildDirectory), - testDirectory).chain((_) { + testDirectory).then((_) { Path extensionDartFile = scriptDirectory.append('test_extension.dart'); return copyFileToDirectory(extensionDartFile, testDirectory); - }).chain((_) { + }).then((_) { Path testExtensionTesterFile = scriptDirectory.append('test_extension_tester.dart'); return copyFileToDirectory(testExtensionTesterFile, testDirectory); - }).chain((_) { + }).then((_) { Path script = testDirectory.append('test_extension_tester.dart'); return Process.run(options.executable, [script.toNativePath()]); })..then((ProcessResult result) { Expect.equals(0, result.exitCode); tempDirectory.deleteSync(recursive: true); - })..handleException((_) { + })..catchError((_) { tempDirectory.deleteSync(recursive: true); }); } diff --git a/tests/standalone/io/test_runner_exit_code_test.dart b/tests/standalone/io/test_runner_exit_code_test.dart index 34e9d0b8f92..02d4f50d773 100644 --- a/tests/standalone/io/test_runner_exit_code_test.dart +++ b/tests/standalone/io/test_runner_exit_code_test.dart @@ -5,8 +5,8 @@ import "dart:io"; void runTests(String executable, String script, Iterator iterator) { - if (iterator.hasNext) { - var progressIndicator = iterator.next(); + if (iterator.moveNext()) { + var progressIndicator = iterator.current; Process.run(executable, [script, progressIndicator]).then((result) { Expect.equals(1, result.exitCode); if (progressIndicator == 'buildbot') { @@ -26,6 +26,6 @@ main() { var executable = new Options().executable; var progressTypes = ['compact', 'color', 'line', 'verbose', 'status', 'buildbot']; - var iterator = progressTypes.iterator(); + var iterator = progressTypes.iterator; runTests(executable, script, iterator); } diff --git a/tests/standalone/io/url_encoding_test.dart b/tests/standalone/io/url_encoding_test.dart index 83765bbf769..cee5022bf83 100644 --- a/tests/standalone/io/url_encoding_test.dart +++ b/tests/standalone/io/url_encoding_test.dart @@ -2,6 +2,7 @@ // 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. +import "dart:async"; import "dart:utf"; part "../../../sdk/lib/io/input_stream.dart"; part "../../../sdk/lib/io/output_stream.dart"; @@ -35,7 +36,7 @@ void testParseQueryString() { 'sqrt2' : '\u221A2', 'name' : 'Franti\u0161ek'}[key]); } - Expect.setEquals(map.keys, ['&', '?', 'foo', 'sqrt2', 'name']); + Expect.setEquals(map.keys.toSet(), ['&', '?', 'foo', 'sqrt2', 'name']); } void main() { diff --git a/tests/standalone/io/web_socket_protocol_processor_test.dart b/tests/standalone/io/web_socket_protocol_processor_test.dart index 46356c078dc..0284a057272 100644 --- a/tests/standalone/io/web_socket_protocol_processor_test.dart +++ b/tests/standalone/io/web_socket_protocol_processor_test.dart @@ -72,7 +72,7 @@ List createFrame(bool fin, frameSize += count; // No masking. assert(maskingKey == null); - List frame = new List(frameSize); + List frame = new List.fixedLength(frameSize); int frameIndex = 0; frame[frameIndex++] = (fin ? 0x80 : 0x00) | opcode; if (count < 126) { @@ -133,7 +133,7 @@ void testFullMessages() { void runTest(int from, int to, int step) { for (int messageLength = from; messageLength < to; messageLength += step) { - List message = new List(messageLength); + List message = new List.fixedLength(messageLength); for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF; testMessage(FRAME_OPCODE_TEXT, message); testMessage(FRAME_OPCODE_BINARY, message); @@ -199,7 +199,7 @@ void testFragmentedMessages() { void runTest(int from, int to, int step) { for (int messageLength = from; messageLength < to; messageLength += step) { - List message = new List(messageLength); + List message = new List.fixedLength(messageLength); for (int i = 0; i < messageLength; i++) message[i] = i & 0xFF; testMessageFragmentation(FRAME_OPCODE_TEXT, message); testMessageFragmentation(FRAME_OPCODE_BINARY, message); diff --git a/tests/standalone/out_of_memory_test.dart b/tests/standalone/out_of_memory_test.dart index 1fb36f9b699..016ab2bede3 100644 --- a/tests/standalone/out_of_memory_test.dart +++ b/tests/standalone/out_of_memory_test.dart @@ -6,7 +6,7 @@ void main() { var number_of_ints = 134000000; var exception_thrown = false; try { - List buf = new List(number_of_ints); + List buf = new List.fixedLength(number_of_ints); } on OutOfMemoryError catch (exc) { exception_thrown = true; } diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status index a0b5abbc90d..a10439513f1 100644 --- a/tests/standalone/standalone.status +++ b/tests/standalone/standalone.status @@ -4,9 +4,15 @@ package/invalid_uri_test: Fail, OK # Fails intentionally +io/test_runner_exit_code_test: Fail # used by both a test and the VM. Can be reenabled when we replace the precompiled dart executable in tools. +status_expression_test: Fail # used by both a test and the VM. Can be reenabled when we replace the precompiled dart executable in tools. +io/status_file_parser_test: Fail # used by both a test and the VM. Can be reenabled when we replace the precompiled dart executable in tools. + [ $runtime == vm ] package/package_isolate_test: Fail # Issue 7520. +io/skipping_dart2js_compilations_test: Fail # used by both a test and the VM. Can be reenabled when we replace the precompiled dart executable in tools. + [ $runtime == vm && $checked ] # These tests have type errors on purpose. io/process_invalid_arguments_test: Fail, OK diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart index b5b89935f17..9cbd95a96c6 100644 --- a/tests/utils/dummy_compiler_test.dart +++ b/tests/utils/dummy_compiler_test.dart @@ -4,6 +4,7 @@ // Smoke test of the dart2js compiler API. +import 'dart:async'; library dummy_compiler; import '../../sdk/lib/_internal/compiler/compiler.dart'; diff --git a/tests/utils/json_test.dart b/tests/utils/json_test.dart index ebc83e428d6..f4b65216207 100644 --- a/tests/utils/json_test.dart +++ b/tests/utils/json_test.dart @@ -14,84 +14,82 @@ main() { void testParse() { // Scalars. - Expect.equals(5, JSON.parse(' 5 ')); - Expect.equals(-42, JSON.parse(' -42 ')); - Expect.equals(3, JSON.parse(' 3e0 ')); - Expect.equals(3.14, JSON.parse(' 3.14 ')); - Expect.equals(1.0E-06, JSON.parse(' 1.0E-06 ')); - Expect.equals(0, JSON.parse("0")); - Expect.equals(1, JSON.parse("1")); - Expect.equals(0.1, JSON.parse("0.1")); - Expect.equals(1.1, JSON.parse("1.1")); - Expect.equals(1.1, JSON.parse("1.100000")); - Expect.equals(1.111111, JSON.parse("1.111111")); - Expect.equals(-0, JSON.parse("-0")); - Expect.equals(-1, JSON.parse("-1")); - Expect.equals(-0.1, JSON.parse("-0.1")); - Expect.equals(-1.1, JSON.parse("-1.1")); - Expect.equals(-1.1, JSON.parse("-1.100000")); - Expect.equals(-1.111111, JSON.parse("-1.111111")); - Expect.equals(11, JSON.parse("1.1e1")); - Expect.equals(11, JSON.parse("1.1e+1")); - Expect.equals(0.11, JSON.parse("1.1e-1")); - Expect.equals(11, JSON.parse("1.1E1")); - Expect.equals(11, JSON.parse("1.1E+1")); - Expect.equals(0.11, JSON.parse("1.1E-1")); - Expect.equals(1E0, JSON.parse(" 1E0")); - Expect.equals(1E+0, JSON.parse(" 1E+0")); - Expect.equals(1E-0, JSON.parse(" 1E-0")); - Expect.equals(1E00, JSON.parse(" 1E00")); - Expect.equals(1E+00, JSON.parse(" 1E+00")); - Expect.equals(1E-00, JSON.parse(" 1E-00")); - Expect.equals(1E+10, JSON.parse(" 1E+10")); - Expect.equals(1E+010, JSON.parse(" 1E+010")); - Expect.equals(1E+0010, JSON.parse(" 1E+0010")); - Expect.equals(1E10, JSON.parse(" 1E10")); - Expect.equals(1E010, JSON.parse(" 1E010")); - Expect.equals(1E0010, JSON.parse(" 1E0010")); - Expect.equals(1E-10, JSON.parse(" 1E-10")); - Expect.equals(1E-0010, JSON.parse(" 1E-0010")); - Expect.equals(1E0, JSON.parse(" 1e0")); - Expect.equals(1E+0, JSON.parse(" 1e+0")); - Expect.equals(1E-0, JSON.parse(" 1e-0")); - Expect.equals(1E00, JSON.parse(" 1e00")); - Expect.equals(1E+00, JSON.parse(" 1e+00")); - Expect.equals(1E-00, JSON.parse(" 1e-00")); - Expect.equals(1E+10, JSON.parse(" 1e+10")); - Expect.equals(1E+010, JSON.parse(" 1e+010")); - Expect.equals(1E+0010, JSON.parse(" 1e+0010")); - Expect.equals(1E10, JSON.parse(" 1e10")); - Expect.equals(1E010, JSON.parse(" 1e010")); - Expect.equals(1E0010, JSON.parse(" 1e0010")); - Expect.equals(1E-10, JSON.parse(" 1e-10")); - Expect.equals(1E-0010, JSON.parse(" 1e-0010")); - Expect.equals(true, JSON.parse(' true ')); - Expect.equals(false, JSON.parse(' false')); - Expect.equals(null, JSON.parse(' null ')); - Expect.equals(null, JSON.parse('\n\rnull\t')); - Expect.equals('hi there" bob', JSON.parse(' "hi there\\" bob" ')); - Expect.equals('', JSON.parse(' "" ')); + Expect.equals(5, parse(' 5 ')); + Expect.equals(-42, parse(' -42 ')); + Expect.equals(3, parse(' 3e0 ')); + Expect.equals(3.14, parse(' 3.14 ')); + Expect.equals(1.0E-06, parse(' 1.0E-06 ')); + Expect.equals(0, parse("0")); + Expect.equals(1, parse("1")); + Expect.equals(0.1, parse("0.1")); + Expect.equals(1.1, parse("1.1")); + Expect.equals(1.1, parse("1.100000")); + Expect.equals(1.111111, parse("1.111111")); + Expect.equals(-0, parse("-0")); + Expect.equals(-1, parse("-1")); + Expect.equals(-0.1, parse("-0.1")); + Expect.equals(-1.1, parse("-1.1")); + Expect.equals(-1.1, parse("-1.100000")); + Expect.equals(-1.111111, parse("-1.111111")); + Expect.equals(11, parse("1.1e1")); + Expect.equals(11, parse("1.1e+1")); + Expect.equals(0.11, parse("1.1e-1")); + Expect.equals(11, parse("1.1E1")); + Expect.equals(11, parse("1.1E+1")); + Expect.equals(0.11, parse("1.1E-1")); + Expect.equals(1E0, parse(" 1E0")); + Expect.equals(1E+0, parse(" 1E+0")); + Expect.equals(1E-0, parse(" 1E-0")); + Expect.equals(1E00, parse(" 1E00")); + Expect.equals(1E+00, parse(" 1E+00")); + Expect.equals(1E-00, parse(" 1E-00")); + Expect.equals(1E+10, parse(" 1E+10")); + Expect.equals(1E+010, parse(" 1E+010")); + Expect.equals(1E+0010, parse(" 1E+0010")); + Expect.equals(1E10, parse(" 1E10")); + Expect.equals(1E010, parse(" 1E010")); + Expect.equals(1E0010, parse(" 1E0010")); + Expect.equals(1E-10, parse(" 1E-10")); + Expect.equals(1E-0010, parse(" 1E-0010")); + Expect.equals(1E0, parse(" 1e0")); + Expect.equals(1E+0, parse(" 1e+0")); + Expect.equals(1E-0, parse(" 1e-0")); + Expect.equals(1E00, parse(" 1e00")); + Expect.equals(1E+00, parse(" 1e+00")); + Expect.equals(1E-00, parse(" 1e-00")); + Expect.equals(1E+10, parse(" 1e+10")); + Expect.equals(1E+010, parse(" 1e+010")); + Expect.equals(1E+0010, parse(" 1e+0010")); + Expect.equals(1E10, parse(" 1e10")); + Expect.equals(1E010, parse(" 1e010")); + Expect.equals(1E0010, parse(" 1e0010")); + Expect.equals(1E-10, parse(" 1e-10")); + Expect.equals(1E-0010, parse(" 1e-0010")); + Expect.equals(true, parse(' true ')); + Expect.equals(false, parse(' false')); + Expect.equals(null, parse(' null ')); + Expect.equals(null, parse('\n\rnull\t')); + Expect.equals('hi there" bob', parse(' "hi there\\" bob" ')); + Expect.equals('', parse(' "" ')); // Lists. - Expect.listEquals([], JSON.parse(' [] ')); - Expect.listEquals(["entry"], JSON.parse(' ["entry"] ')); - Expect.listEquals([true, false], JSON.parse(' [true, false] ')); - Expect.listEquals([1, 2, 3], JSON.parse(' [ 1 , 2 , 3 ] ')); + Expect.listEquals([], parse(' [] ')); + Expect.listEquals(["entry"], parse(' ["entry"] ')); + Expect.listEquals([true, false], parse(' [true, false] ')); + Expect.listEquals([1, 2, 3], parse(' [ 1 , 2 , 3 ] ')); // Maps. - Expect.mapEquals({}, JSON.parse(' {} ')); - Expect.mapEquals({"key": "value"}, JSON.parse(' {"key": "value" } ')); + Expect.mapEquals({}, parse(' {} ')); + Expect.mapEquals({"key": "value"}, parse(' {"key": "value" } ')); Expect.mapEquals({"key1": 1, "key2": 2}, - JSON.parse(' {"key1": 1, "key2": 2} ')); + parse(' {"key1": 1, "key2": 2} ')); Expect.mapEquals({"key1": 1}, - JSON.parse(' { "key1" : 1 } ')); + parse(' { "key1" : 1 } ')); } void testParseInvalid() { void testString(String s) { - // TODO(ajohnsen): Require JSONParseException exception once all JSON libs - // have been updated. - Expect.throws(() => JSON.parse(s)); + Expect.throws(() => parse(s), (e) => e is FormatException); } // Scalars testString(""); @@ -137,43 +135,43 @@ void testParseInvalid() { } void testEscaping() { - Expect.stringEquals('""', JSON.stringify('')); - Expect.stringEquals('"\\u0000"', JSON.stringify('\u0000')); - Expect.stringEquals('"\\u0001"', JSON.stringify('\u0001')); - Expect.stringEquals('"\\u0002"', JSON.stringify('\u0002')); - Expect.stringEquals('"\\u0003"', JSON.stringify('\u0003')); - Expect.stringEquals('"\\u0004"', JSON.stringify('\u0004')); - Expect.stringEquals('"\\u0005"', JSON.stringify('\u0005')); - Expect.stringEquals('"\\u0006"', JSON.stringify('\u0006')); - Expect.stringEquals('"\\u0007"', JSON.stringify('\u0007')); - Expect.stringEquals('"\\b"', JSON.stringify('\u0008')); - Expect.stringEquals('"\\t"', JSON.stringify('\u0009')); - Expect.stringEquals('"\\n"', JSON.stringify('\u000a')); - Expect.stringEquals('"\\u000b"', JSON.stringify('\u000b')); - Expect.stringEquals('"\\f"', JSON.stringify('\u000c')); - Expect.stringEquals('"\\r"', JSON.stringify('\u000d')); - Expect.stringEquals('"\\u000e"', JSON.stringify('\u000e')); - Expect.stringEquals('"\\u000f"', JSON.stringify('\u000f')); - Expect.stringEquals('"\\u0010"', JSON.stringify('\u0010')); - Expect.stringEquals('"\\u0011"', JSON.stringify('\u0011')); - Expect.stringEquals('"\\u0012"', JSON.stringify('\u0012')); - Expect.stringEquals('"\\u0013"', JSON.stringify('\u0013')); - Expect.stringEquals('"\\u0014"', JSON.stringify('\u0014')); - Expect.stringEquals('"\\u0015"', JSON.stringify('\u0015')); - Expect.stringEquals('"\\u0016"', JSON.stringify('\u0016')); - Expect.stringEquals('"\\u0017"', JSON.stringify('\u0017')); - Expect.stringEquals('"\\u0018"', JSON.stringify('\u0018')); - Expect.stringEquals('"\\u0019"', JSON.stringify('\u0019')); - Expect.stringEquals('"\\u001a"', JSON.stringify('\u001a')); - Expect.stringEquals('"\\u001b"', JSON.stringify('\u001b')); - Expect.stringEquals('"\\u001c"', JSON.stringify('\u001c')); - Expect.stringEquals('"\\u001d"', JSON.stringify('\u001d')); - Expect.stringEquals('"\\u001e"', JSON.stringify('\u001e')); - Expect.stringEquals('"\\u001f"', JSON.stringify('\u001f')); - Expect.stringEquals('"\\\""', JSON.stringify('"')); - Expect.stringEquals('"\\\\"', JSON.stringify('\\')); + Expect.stringEquals('""', stringify('')); + Expect.stringEquals('"\\u0000"', stringify('\u0000')); + Expect.stringEquals('"\\u0001"', stringify('\u0001')); + Expect.stringEquals('"\\u0002"', stringify('\u0002')); + Expect.stringEquals('"\\u0003"', stringify('\u0003')); + Expect.stringEquals('"\\u0004"', stringify('\u0004')); + Expect.stringEquals('"\\u0005"', stringify('\u0005')); + Expect.stringEquals('"\\u0006"', stringify('\u0006')); + Expect.stringEquals('"\\u0007"', stringify('\u0007')); + Expect.stringEquals('"\\b"', stringify('\u0008')); + Expect.stringEquals('"\\t"', stringify('\u0009')); + Expect.stringEquals('"\\n"', stringify('\u000a')); + Expect.stringEquals('"\\u000b"', stringify('\u000b')); + Expect.stringEquals('"\\f"', stringify('\u000c')); + Expect.stringEquals('"\\r"', stringify('\u000d')); + Expect.stringEquals('"\\u000e"', stringify('\u000e')); + Expect.stringEquals('"\\u000f"', stringify('\u000f')); + Expect.stringEquals('"\\u0010"', stringify('\u0010')); + Expect.stringEquals('"\\u0011"', stringify('\u0011')); + Expect.stringEquals('"\\u0012"', stringify('\u0012')); + Expect.stringEquals('"\\u0013"', stringify('\u0013')); + Expect.stringEquals('"\\u0014"', stringify('\u0014')); + Expect.stringEquals('"\\u0015"', stringify('\u0015')); + Expect.stringEquals('"\\u0016"', stringify('\u0016')); + Expect.stringEquals('"\\u0017"', stringify('\u0017')); + Expect.stringEquals('"\\u0018"', stringify('\u0018')); + Expect.stringEquals('"\\u0019"', stringify('\u0019')); + Expect.stringEquals('"\\u001a"', stringify('\u001a')); + Expect.stringEquals('"\\u001b"', stringify('\u001b')); + Expect.stringEquals('"\\u001c"', stringify('\u001c')); + Expect.stringEquals('"\\u001d"', stringify('\u001d')); + Expect.stringEquals('"\\u001e"', stringify('\u001e')); + Expect.stringEquals('"\\u001f"', stringify('\u001f')); + Expect.stringEquals('"\\\""', stringify('"')); + Expect.stringEquals('"\\\\"', stringify('\\')); Expect.stringEquals('"Got \\b, \\f, \\n, \\r, \\t, \\u0000, \\\\, and \\"."', - JSON.stringify('Got \b, \f, \n, \r, \t, \u0000, \\, and ".')); + stringify('Got \b, \f, \n, \r, \t, \u0000, \\, and ".')); Expect.stringEquals('"Got \\b\\f\\n\\r\\t\\u0000\\\\\\"."', - JSON.stringify('Got \b\f\n\r\t\u0000\\".')); + stringify('Got \b\f\n\r\t\u0000\\".')); } diff --git a/tests/utils/recursive_import_test.dart b/tests/utils/recursive_import_test.dart index ef53e6959b0..7820774372e 100644 --- a/tests/utils/recursive_import_test.dart +++ b/tests/utils/recursive_import_test.dart @@ -4,6 +4,7 @@ // Test of "recursive" imports using the dart2js compiler API. +import 'dart:async'; import '../../sdk/lib/_internal/compiler/compiler.dart'; import 'dart:uri'; diff --git a/tests/utils/uri_test.dart b/tests/utils/uri_test.dart index 202304eb02b..d72b30844a4 100644 --- a/tests/utils/uri_test.dart +++ b/tests/utils/uri_test.dart @@ -12,6 +12,10 @@ testUri(String uri, bool isAbsolute) { Expect.equals(isAbsolute, new Uri(uri).isAbsolute()); Expect.stringEquals(uri, new Uri.fromString(uri).toString()); Expect.stringEquals(uri, new Uri(uri).toString()); + + // Test equals and hashCode members. + Expect.equals(new Uri(uri), new Uri(uri)); + Expect.equals(new Uri(uri).hashCode, new Uri(uri).hashCode); } testEncodeDecode(String orig, String encoded) { diff --git a/tests/utils/utils.status b/tests/utils/utils.status index e421ea372db..4a989fecf43 100644 --- a/tests/utils/utils.status +++ b/tests/utils/utils.status @@ -2,6 +2,10 @@ # 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. +# TODO(floitsch): dart2js is currently broken because of the iterator change. +dummy_compiler_test: Fail +recursive_import_test: Fail + [ $arch == simarm ] *: Skip diff --git a/tools/create_sdk.py b/tools/create_sdk.py index 321ab219e63..825d2fa2b60 100755 --- a/tools/create_sdk.py +++ b/tools/create_sdk.py @@ -23,6 +23,7 @@ # ......dart_debugger_api.h # ....lib/ # ......_internal/ +# ......async/ # ......collection/ # ......core/ # ......crypto/ @@ -197,8 +198,8 @@ def Main(argv): # os.makedirs(join(LIB, 'html')) - for library in ['_internal', 'collection', 'core', 'crypto', 'io', 'isolate', - join('html', 'dart2js'), join('html', 'dartium'), + for library in ['_internal', 'async', 'collection', 'core', 'crypto', 'io', + 'isolate', join('html', 'dart2js'), join('html', 'dartium'), join('html', 'html_common'), join('indexed_db', 'dart2js'), join('indexed_db', 'dartium'), 'json', 'math', 'mirrors', 'scalarlist', join('svg', 'dart2js'), join('svg', 'dartium'), diff --git a/tools/ddbg.dart b/tools/ddbg.dart index 3c2f643b07f..c7febadf342 100644 --- a/tools/ddbg.dart +++ b/tools/ddbg.dart @@ -5,10 +5,9 @@ // Simple interactive debugger shell that connects to the Dart VM's debugger // connection port. -#import("dart:io"); -#import("dart:json"); -#import("dart:math", prefix: "Math"); -#import("dart:utf"); +import "dart:io"; +import "dart:json"; +import "dart:utf"; Map outstandingCommands; @@ -67,9 +66,9 @@ Future sendCmd(Map cmd) { int id = cmd["id"]; outstandingCommands[id] = completer; if (verbose) { - print("sending: '${JSON.stringify(cmd)}'"); + print("sending: '${jsonStringify(cmd)}'"); } - vmStream.writeString(JSON.stringify(cmd)); + vmStream.writeString(jsonStringify(cmd)); return completer.future; } @@ -103,10 +102,10 @@ void processCommand(String cmdLine) { var url, line; if (args.length == 2) { url = stackTrace[0]["location"]["url"]; - line = Math.parseInt(args[1]); + line = int.parse(args[1]); } else { url = args[1]; - line = Math.parseInt(args[2]); + line = int.parse(args[2]); } var cmd = { "id": seqNum, "command": "setBreakpoint", @@ -118,19 +117,19 @@ void processCommand(String cmdLine) { var cmd = { "id": seqNum, "command": "removeBreakpoint", "params": { "isolateId" : isolate_id, - "breakpointId": Math.parseInt(args[1]) } }; + "breakpointId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGenericResponse(result)); } else if (command == "ls" && args.length == 2) { var cmd = { "id": seqNum, "command": "getScriptURLs", "params": { "isolateId" : isolate_id, - "libraryId": Math.parseInt(args[1]) } }; + "libraryId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGetScriptsResponse(result)); } else if (command == "po" && args.length == 2) { var cmd = { "id": seqNum, "command": "getObjectProperties", "params": { "isolateId" : isolate_id, - "objectId": Math.parseInt(args[1]) } }; + "objectId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGetObjPropsResponse(result)); } else if (command == "pl" && args.length >= 3) { var cmd; @@ -138,47 +137,47 @@ void processCommand(String cmdLine) { cmd = { "id": seqNum, "command": "getListElements", "params": { "isolateId" : isolate_id, - "objectId": Math.parseInt(args[1]), - "index": Math.parseInt(args[2]) } }; + "objectId": int.parse(args[1]), + "index": int.parse(args[2]) } }; } else { cmd = { "id": seqNum, "command": "getListElements", "params": { "isolateId" : isolate_id, - "objectId": Math.parseInt(args[1]), - "index": Math.parseInt(args[2]), - "length": Math.parseInt(args[3]) } }; + "objectId": int.parse(args[1]), + "index": int.parse(args[2]), + "length": int.parse(args[3]) } }; } sendCmd(cmd).then((result) => handleGetListResponse(result)); } else if (command == "pc" && args.length == 2) { var cmd = { "id": seqNum, "command": "getClassProperties", "params": { "isolateId" : isolate_id, - "classId": Math.parseInt(args[1]) } }; + "classId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGetClassPropsResponse(result)); } else if (command == "plib" && args.length == 2) { var cmd = { "id": seqNum, "command": "getLibraryProperties", "params": {"isolateId" : isolate_id, - "libraryId": Math.parseInt(args[1]) } }; + "libraryId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGetLibraryPropsResponse(result)); } else if (command == "slib" && args.length == 3) { var cmd = { "id": seqNum, "command": "setLibraryProperties", "params": {"isolateId" : isolate_id, - "libraryId": Math.parseInt(args[1]), + "libraryId": int.parse(args[1]), "debuggingEnabled": args[2] } }; sendCmd(cmd).then((result) => handleSetLibraryPropsResponse(result)); } else if (command == "pg" && args.length == 2) { var cmd = { "id": seqNum, "command": "getGlobalVariables", "params": { "isolateId" : isolate_id, - "libraryId": Math.parseInt(args[1]) } }; + "libraryId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGetGlobalVarsResponse(result)); } else if (command == "gs" && args.length == 3) { var cmd = { "id": seqNum, "command": "getScriptSource", "params": { "isolateId" : isolate_id, - "libraryId": Math.parseInt(args[1]), + "libraryId": int.parse(args[1]), "url": args[2] } }; sendCmd(cmd).then((result) => handleGetSourceResponse(result)); } else if (command == "epi" && args.length == 2) { @@ -190,7 +189,7 @@ void processCommand(String cmdLine) { } else if (command == "i" && args.length == 2) { var cmd = { "id": seqNum, "command": "interrupt", - "params": { "isolateId": Math.parseInt(args[1]) } }; + "params": { "isolateId": int.parse(args[1]) } }; sendCmd(cmd).then((result) => handleGenericResponse(result)); } else if (command == "q") { quitShell(); @@ -412,7 +411,7 @@ void handlePausedEvent(msg) { void processVmMessage(String json) { - var msg = JSON.parse(json); + var msg = parseJson(json); if (msg == null) { return; } @@ -483,7 +482,7 @@ void processVmData(String data) { * Skip past a JSON object value. * The object value must start with '{' and continues to the * matching '}'. No attempt is made to otherwise validate the contents - * as JSON. If it is invalid, a later [JSON.parse] will fail. + * as JSON. If it is invalid, a later [parseJson] will fail. */ int jsonObjectLength(String string) { int skipWhitespace(int index) { @@ -509,14 +508,14 @@ int jsonObjectLength(String string) { index = skipWhitespace(index); // Bail out if the first non-whitespace character isn't '{'. if (index == string.length || string[index] != '{') return 0; - int nexting = 0; + int nesting = 0; while (index < string.length) { String char = string[index++]; if (char == '{') { - nexting++; + nesting++; } else if (char == '}') { - nexting--; - if (nexting == 0) return index; + nesting--; + if (nesting == 0) return index; } else if (char == '"') { // Strings can contain braces. Skip their content. index = skipString(index); diff --git a/tools/dom/scripts/idlparser.dart b/tools/dom/scripts/idlparser.dart index 11ecad3338a..f0c6d60426d 100644 --- a/tools/dom/scripts/idlparser.dart +++ b/tools/dom/scripts/idlparser.dart @@ -34,10 +34,10 @@ class IDLModule extends IDLNode { List elements) { setExtAttrs(extAttrs); this.annotations = annotations; - this.interfaces = elements.filter((e) => e is IDLInterface); - this.typedefs = elements.filter((e) => e is IDLTypeDef); + this.interfaces = elements.where((e) => e is IDLInterface).toList(); + this.typedefs = elements.where((e) => e is IDLTypeDef).toList(); this.implementsStatements = - elements.filter((e) => e is IDLImplementsStatement); + elements.where((e) => e is IDLImplementsStatement).toList(); } toString() => ''; @@ -101,10 +101,10 @@ class IDLInterface extends IDLNode { this.annotations = ann; if (this.parents == null) this.parents = []; - operations = members.filter((e) => e is IDLOperation); - attributes = members.filter((e) => e is IDLAttribute); - constants = members.filter((e) => e is IDLConstant); - snippets = members.filter((e) => e is IDLSnippet); + operations = members.where((e) => e is IDLOperation).toList(); + attributes = members.where((e) => e is IDLAttribute).toList(); + constants = members.where((e) => e is IDLConstant).toList(); + snippets = members.where((e) => e is IDLSnippet).toList(); isSupplemental = extAttrs.has('Supplemental'); isNoInterfaceObject = extAttrs.has('NoInterfaceObject'); diff --git a/tools/dom/src/AttributeMap.dart b/tools/dom/src/AttributeMap.dart index 0bf43a64a19..d309a71818a 100644 --- a/tools/dom/src/AttributeMap.dart +++ b/tools/dom/src/AttributeMap.dart @@ -161,7 +161,7 @@ class _DataAttributeMap implements Map { // interface Map // TODO: Use lazy iterator when it is available on Map. - bool containsValue(String value) => values.some((v) => v == value); + bool containsValue(String value) => values.any((v) => v == value); bool containsKey(String key) => $dom_attributes.containsKey(_attr(key)); diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart index 7acc4e54aaf..ccb6d90ee1a 100644 --- a/tools/dom/src/CssClassSet.dart +++ b/tools/dom/src/CssClassSet.dart @@ -34,7 +34,7 @@ abstract class CssClassSet implements Set { bool get frozen => false; // interface Iterable - BEGIN - Iterator iterator() => readClasses().iterator(); + Iterator get iterator => readClasses().iterator; // interface Iterable - END // interface Collection - BEGIN @@ -42,13 +42,15 @@ abstract class CssClassSet implements Set { readClasses().forEach(f); } - Collection map(f(String element)) => readClasses().map(f); + String join([String separator]) => readClasses().join(separator); - Collection filter(bool f(String element)) => readClasses().filter(f); + Iterable mappedBy(f(String element)) => readClasses().mappedBy(f); + + Iterable where(bool f(String element)) => readClasses().where(f); bool every(bool f(String element)) => readClasses().every(f); - bool some(bool f(String element)) => readClasses().some(f); + bool any(bool f(String element)) => readClasses().any(f); bool get isEmpty => readClasses().isEmpty; @@ -76,13 +78,13 @@ abstract class CssClassSet implements Set { return result; } - void addAll(Collection collection) { + void addAll(Iterable iterable) { // TODO - see comment above about validation - _modify((s) => s.addAll(collection)); + _modify((s) => s.addAll(iterable)); } - void removeAll(Collection collection) { - _modify((s) => s.removeAll(collection)); + void removeAll(Iterable iterable) { + _modify((s) => s.removeAll(iterable)); } bool isSubsetOf(Collection collection) => diff --git a/tools/dom/src/Isolates.dart b/tools/dom/src/Isolates.dart index 7fbf3d4537a..5bdf35bb22d 100644 --- a/tools/dom/src/Isolates.dart +++ b/tools/dom/src/Isolates.dart @@ -95,7 +95,7 @@ class _RemoteSendPortSync implements SendPortSync { var source = '$target-result'; var result = null; var listener = (Event e) { - result = JSON.parse(_getPortSyncEventData(e)); + result = json.parse(_getPortSyncEventData(e)); }; window.on[source].add(listener); _dispatchEvent(target, [source, message]); @@ -167,7 +167,7 @@ class ReceivePortSync { _callback = callback; if (_listener == null) { _listener = (Event e) { - var data = JSON.parse(_getPortSyncEventData(e)); + var data = json.parse(_getPortSyncEventData(e)); var replyTo = data[0]; var message = _deserialize(data[1]); var result = _callback(message); @@ -198,7 +198,7 @@ class ReceivePortSync { get _isolateId => ReceivePortSync._isolateId; void _dispatchEvent(String receiver, var message) { - var event = new CustomEvent(receiver, false, false, JSON.stringify(message)); + var event = new CustomEvent(receiver, false, false, json.stringify(message)); window.$dom_dispatchEvent(event); } diff --git a/tools/dom/src/KeyboardEventController.dart b/tools/dom/src/KeyboardEventController.dart index f949b32724a..1e0f97a82c6 100644 --- a/tools/dom/src/KeyboardEventController.dart +++ b/tools/dom/src/KeyboardEventController.dart @@ -150,7 +150,7 @@ class KeyboardEventController { /** Determine if caps lock is one of the currently depressed keys. */ bool get _capsLockOn => - _keyDownList.some((var element) => element.keyCode == KeyCode.CAPS_LOCK); + _keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK); /** * Given the previously recorded keydown key codes, see if we can determine @@ -379,7 +379,7 @@ class KeyboardEventController { // keyCode/which for non printable keys. e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]; } - e._shadowAltKey = _keyDownList.some((var element) => element.altKey); + e._shadowAltKey = _keyDownList.any((var element) => element.altKey); _dispatch(e); } @@ -393,7 +393,8 @@ class KeyboardEventController { } } if (toRemove != null) { - _keyDownList = _keyDownList.filter((element) => element != toRemove); + _keyDownList = + _keyDownList.where((element) => element != toRemove).toList(); } else if (_keyDownList.length > 0) { // This happens when we've reached some international keyboard case we // haven't accounted for or we haven't correctly eliminated all browser diff --git a/tools/dom/src/Serialization.dart b/tools/dom/src/Serialization.dart index 4db5c0d285b..0d1cc827507 100644 --- a/tools/dom/src/Serialization.dart +++ b/tools/dom/src/Serialization.dart @@ -90,15 +90,15 @@ abstract class _Serializer extends _MessageTraverser { int id = _nextFreeRefId++; _visited[map] = id; - var keys = _serializeList(map.keys); - var values = _serializeList(map.values); + var keys = _serializeList(map.keys.toList()); + var values = _serializeList(map.values.toList()); // TODO(floitsch): we are losing the generic type. return ['map', id, keys, values]; } _serializeList(List list) { int len = list.length; - var result = new List(len); + var result = new List.fixedLength(len); for (int i = 0; i < len; i++) { result[i] = _dispatch(list[i]); } diff --git a/tools/dom/src/_ListIterators.dart b/tools/dom/src/_ListIterators.dart index 9812718eca3..821ef514e4b 100644 --- a/tools/dom/src/_ListIterators.dart +++ b/tools/dom/src/_ListIterators.dart @@ -5,31 +5,53 @@ part of html; // Iterator for arrays with fixed size. -class FixedSizeListIterator extends _VariableSizeListIterator { +class FixedSizeListIterator implements Iterator { + final List _array; + final int _length; // Cache array length for faster access. + int _position; + T _current; + FixedSizeListIterator(List array) - : super(array), + : _array = array, + _position = -1, _length = array.length; - bool get hasNext => _length > _pos; + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; + } + _current = null; + _position = _length; + return false; + } - final int _length; // Cache array length for faster access. + T get current => _current; } // Iterator for arrays with variable size. class _VariableSizeListIterator implements Iterator { + final List _array; + int _position; + T _current; + _VariableSizeListIterator(List array) : _array = array, - _pos = 0; + _position = -1; - bool get hasNext => _array.length > _pos; - - T next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextPosition = _position + 1; + if (nextPosition < _array.length) { + _current = _array[nextPosition]; + _position = nextPosition; + return true; } - return _array[_pos++]; + _current = null; + _position = _array.length; + return false; } - final List _array; - int _pos; + T get current => _current; } diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart index 84d9af80bdc..2f91ab1af59 100644 --- a/tools/dom/src/native_DOMImplementation.dart +++ b/tools/dom/src/native_DOMImplementation.dart @@ -8,7 +8,7 @@ class _Utils { static List convertToList(List list) { // FIXME: [possible optimization]: do not copy the array if Dart_IsArray is fine w/ it. final length = list.length; - List result = new List(length); + List result = new List.fixedLength(length); result.setRange(0, length, list); return result; } diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate index c0d59d3c52a..547e4df9365 100644 --- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate +++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate @@ -7,11 +7,12 @@ library html; +import 'dart:async'; import 'dart:collection'; import 'dart:html_common'; import 'dart:indexed_db'; import 'dart:isolate'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:math'; // Not actually used, but imported since dart:html can generate these objects. import 'dart:svg' as svg; diff --git a/tools/dom/templates/html/dart2js/impl_Window.darttemplate b/tools/dom/templates/html/dart2js/impl_Window.darttemplate index dbe3849fe84..93f988485ff 100644 --- a/tools/dom/templates/html/dart2js/impl_Window.darttemplate +++ b/tools/dom/templates/html/dart2js/impl_Window.darttemplate @@ -143,7 +143,7 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS native "@*DOMWindow" { * registered under [name]. */ SendPortSync lookupPort(String name) { - var port = JSON.parse(document.documentElement.attributes['dart-port:$name']); + var port = json.parse(document.documentElement.attributes['dart-port:$name']); return _deserialize(port); } @@ -154,7 +154,7 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS native "@*DOMWindow" { */ void registerPort(String name, var port) { var serialized = _serialize(port); - document.documentElement.attributes['dart-port:$name'] = JSON.stringify(serialized); + document.documentElement.attributes['dart-port:$name'] = json.stringify(serialized); } /// @domName Window.console; @docsEditable true diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate index 2d1d6cfff5e..d9cc41f488f 100644 --- a/tools/dom/templates/html/dartium/html_dartium.darttemplate +++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate @@ -7,11 +7,12 @@ library html; +import 'dart:async'; import 'dart:collection'; import 'dart:html_common'; import 'dart:indexed_db'; import 'dart:isolate'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:nativewrappers'; // Not actually used, but imported since dart:html can generate these objects. import 'dart:svg' as svg; @@ -75,7 +76,7 @@ var _callPortLastResult = null; _callPortSync(num id, var message) { if (!_callPortInitialized) { window.on['js-result'].add((event) { - _callPortLastResult = JSON.parse(_getPortSyncEventData(event)); + _callPortLastResult = json.parse(_getPortSyncEventData(event)); }, false); _callPortInitialized = true; } diff --git a/tools/dom/templates/html/dartium/impl_Window.darttemplate b/tools/dom/templates/html/dartium/impl_Window.darttemplate index d463470cc7c..286114d08cb 100644 --- a/tools/dom/templates/html/dartium/impl_Window.darttemplate +++ b/tools/dom/templates/html/dartium/impl_Window.darttemplate @@ -21,7 +21,7 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { * registered under [name]. */ lookupPort(String name) { - var port = JSON.parse(document.documentElement.attributes['dart-port:$name']); + var port = json.parse(document.documentElement.attributes['dart-port:$name']); return _deserialize(port); } @@ -32,7 +32,7 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { */ registerPort(String name, var port) { var serialized = _serialize(port); - document.documentElement.attributes['dart-port:$name'] = JSON.stringify(serialized); + document.documentElement.attributes['dart-port:$name'] = json.stringify(serialized); } $!MEMBERS diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate index 3971f831a21..72e2f123529 100644 --- a/tools/dom/templates/html/impl/impl_Document.darttemplate +++ b/tools/dom/templates/html/impl/impl_Document.darttemplate @@ -62,7 +62,7 @@ $!MEMBERS final mutableMatches = $dom_getElementsByName( selectors.substring(7,selectors.length - 2)); int len = mutableMatches.length; - final copyOfMatches = new List(len); + final copyOfMatches = new List.fixedLength(len); for (int i = 0; i < len; ++i) { copyOfMatches[i] = mutableMatches[i]; } @@ -70,7 +70,7 @@ $!MEMBERS } else if (new RegExp("^[*a-zA-Z0-9]+\$").hasMatch(selectors)) { final mutableMatches = $dom_getElementsByTagName(selectors); int len = mutableMatches.length; - final copyOfMatches = new List(len); + final copyOfMatches = new List.fixedLength(len); for (int i = 0; i < len; ++i) { copyOfMatches[i] = mutableMatches[i]; } diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate index 1ef1b731b37..72af8a83634 100644 --- a/tools/dom/templates/html/impl/impl_Element.darttemplate +++ b/tools/dom/templates/html/impl/impl_Element.darttemplate @@ -15,14 +15,22 @@ class _ChildrenElementList implements List { : _childElements = element.$dom_children, _element = element; - List _toList() { - final output = new List(_childElements.length); + List toList() { + final output = new List.fixedLength(_childElements.length); for (int i = 0, len = _childElements.length; i < len; i++) { output[i] = _childElements[i]; } return output; } + Set toSet() { + final output = new Set(_childElements.length); + for (int i = 0, len = _childElements.length; i < len; i++) { + output.add(_childElements[i]); + } + return output; + } + bool contains(Element element) => _childElements.contains(element); void forEach(void f(Element element)) { @@ -31,46 +39,71 @@ class _ChildrenElementList implements List { } } - List filter(bool f(Element element)) { - final output = []; - forEach((Element element) { - if (f(element)) { - output.add(element); - } - }); - return new _FrozenElementList._wrap(output); - } - bool every(bool f(Element element)) { for (Element element in this) { if (!f(element)) { return false; } - }; + } return true; } - bool some(bool f(Element element)) { + bool any(bool f(Element element)) { for (Element element in this) { if (f(element)) { return true; } - }; + } return false; } - Collection map(f(Element element)) { - final out = []; - for (Element el in this) { - out.add(f(el)); - } - return out; + String join([String separator]) { + return Collections.joinList(this, separator); } + List mappedBy(f(Element element)) { + return new MappedList(this, f); + } + + Iterable where(bool f(Element element)) + => new WhereIterable(this, f); + bool get isEmpty { return _element.$dom_firstElementChild == null; } + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(Element value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(Element value)) { + return new SkipWhileIterable(this, test); + } + + Element firstMatching(bool test(Element value), {Element orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Element singleMatching(bool test(Element value)) { + return Collections.singleMatching(this, test); + } + + Element elementAt(int index) { + return this[index]; + } + int get length { return _childElements.length; } @@ -95,10 +128,10 @@ class _ChildrenElementList implements List { Element addLast(Element value) => add(value); - Iterator iterator() => _toList().iterator(); + Iterator get iterator => toList().iterator; - void addAll(Collection collection) { - for (Element element in collection) { + void addAll(Iterable iterable) { + for (Element element in iterable) { _element.$dom_appendChild(element); } } @@ -159,12 +192,29 @@ class _ChildrenElementList implements List { } Element get first { - return _element.$dom_firstElementChild; + Element result = _element.$dom_firstElementChild; + if (result == null) throw new StateError("No elements"); + return result; } Element get last { - return _element.$dom_lastElementChild; + Element result = _element.$dom_lastElementChild; + if (result == null) throw new StateError("No elements"); + return result; + } + + Element get single { + if (length > 1) throw new StateError("More than one element"); + return first; + } + + Element min([int compare(Element a, Element b)]) { + return _Collections.minInList(this, compare); + } + + Element max([int compare(Element a, Element b)]) { + return _Collections.maxInList(this, compare); } } @@ -190,22 +240,17 @@ class _FrozenElementList implements List { } } - Collection map(f(Element element)) { - final out = []; - for (Element el in this) { - out.add(f(el)); - } - return out; + String join([String separator]) { + return Collections.joinList(this, separator); } - List filter(bool f(Element element)) { - final out = []; - for (Element el in this) { - if (f(el)) out.add(el); - } - return out; + List mappedBy(f(Element element)) { + return new MappedList(this, f); } + Iterable where(bool f(Element element)) + => new WhereIterable(this, f); + bool every(bool f(Element element)) { for(Element element in this) { if (!f(element)) { @@ -215,7 +260,7 @@ class _FrozenElementList implements List { return true; } - bool some(bool f(Element element)) { + bool any(bool f(Element element)) { for(Element element in this) { if (f(element)) { return true; @@ -224,6 +269,38 @@ class _FrozenElementList implements List { return false; } + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(T value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(T value)) { + return new SkipWhileIterable(this, test); + } + + Element firstMatching(bool test(Element value), {Element orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Element lastMatching(bool test(Element value), {Element orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Element singleMatching(bool test(Element value)) { + return Collections.singleMatching(this, test); + } + + Element elementAt(int index) { + return this[index]; + } + bool get isEmpty => _nodeList.isEmpty; int get length => _nodeList.length; @@ -246,9 +323,9 @@ class _FrozenElementList implements List { throw new UnsupportedError(''); } - Iterator iterator() => new _FrozenElementListIterator(this); + Iterator get iterator => new _FrozenElementListIterator(this); - void addAll(Collection collection) { + void addAll(Iterable iterable) { throw new UnsupportedError(''); } @@ -297,6 +374,16 @@ class _FrozenElementList implements List { Element get first => _nodeList.first; Element get last => _nodeList.last; + + Element get single => _nodeList.single; + + Element min([int compare(Element a, Element b)]) { + return _Collections.minInList(this, compare); + } + + Element max([int compare(Element a, Element b)]) { + return _Collections.maxInList(this, compare); + } } class _FrozenElementListIterator implements Iterator { @@ -306,21 +393,28 @@ class _FrozenElementListIterator implements Iterator { _FrozenElementListIterator(this._list); /** - * Gets the next element in the iteration. Throws a - * [StateError("No more elements")] if no element is left. + * Moves to the next element. Returns true if the iterator is positioned + * at an element. Returns false if it is positioned after the last element. */ - Element next() { - if (!hasNext) { - throw new StateError("No more elements"); + bool moveNext() { + int nextIndex = _index + 1; + if (nextIndex < _list.length) { + _current = _list[nextIndex]; + _index = nextIndex; + return true; } - - return _list[_index++]; + _index = _list.length; + _current = null; + return false; } /** - * Returns whether the [Iterator] has elements left. + * Returns the element the [Iterator] is positioned at. + * + * Return [:null:] if the iterator is positioned before the first, or + * after the last element. */ - bool get hasNext => _index < _list.length; + E get current => _current; } class _ElementCssClassSet extends CssClassSet { @@ -344,7 +438,7 @@ class _ElementCssClassSet extends CssClassSet { void writeClasses(Set s) { List list = new List.from(s); - _element.$dom_className = Strings.join(list, ' '); + _element.$dom_className = s.join(' '); } } diff --git a/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate index ad44ea673be..5d8210b1d08 100644 --- a/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate +++ b/tools/dom/templates/html/impl/impl_HTMLSelectElement.darttemplate @@ -11,13 +11,13 @@ $!MEMBERS // Override default options, since IE returns SelectElement itself and it // does not operate as a List. List get options { - return this.children.filter((e) => e is OptionElement); + return this.children.where((e) => e is OptionElement).toList(); } List get selectedOptions { // IE does not change the selected flag for single-selection items. if (this.multiple) { - return this.options.filter((o) => o.selected); + return this.options.where((o) => o.selected).toList(); } else { return [this.options[this.selectedIndex]]; } diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate index 85671be8f33..74fe51e4e42 100644 --- a/tools/dom/templates/html/impl/impl_Node.darttemplate +++ b/tools/dom/templates/html/impl/impl_Node.darttemplate @@ -16,13 +16,49 @@ class _ChildNodeListLazy implements List { $if DART2JS - Node get first => JS('Node', '#.firstChild', _this); - Node get last => JS('Node', '#.lastChild', _this); + Node get first { + Node result = JS('Node', '#.firstChild', _this); + if (result == null) throw new StateError("No elements"); + return result; + } + Node get last { + Node result = JS('Node', '#.lastChild', _this); + if (result == null) throw new StateError("No elements"); + return result; + } + Node get single { + int l = this.length; + if (l == 0) throw new StateError("No elements"); + if (l > 1) throw new StateError("More than one element"); + return JS('Node', '#.firstChild', _this); + } $else - Node get first => _this.$dom_firstChild; - Node get last => _this.$dom_lastChild; + Node get first { + Node result = _this.$dom_firstChild; + if (result == null) throw new StateError("No elements"); + return result; + } + Node get last { + Node result = _this.$dom_lastChild; + if (result == null) throw new StateError("No elements"); + return result; + } + Node get single { + int l = this.length; + if (l == 0) throw new StateError("No elements"); + if (l > 1) throw new StateError("More than one element"); + return _this.$dom_firstChild; + } $endif + Node min([int compare(Node a, Node b)]) { + return _Collections.minInList(this, compare); + } + + Node max([int compare(Node a, Node b)]) { + return _Collections.maxInList(this, compare); + } + void add(Node value) { _this.$dom_appendChild(value); } @@ -32,8 +68,8 @@ $endif } - void addAll(Collection collection) { - for (Node node in collection) { + void addAll(Iterable iterable) { + for (Node node in iterable) { _this.$dom_appendChild(node); } } @@ -62,7 +98,7 @@ $endif _this.$dom_replaceChild(value, this[index]); } - Iterator iterator() => _this.$dom_childNodes.iterator(); + Iterator get iterator => _this.$dom_childNodes.iterator; // TODO(jacobr): We can implement these methods much more efficiently by // looking up the nodeList only once instead of once per iteration. @@ -75,19 +111,56 @@ $endif return Collections.reduce(this, initialValue, combine); } - Collection map(f(Node element)) => Collections.map(this, [], f); + String join([String separator]) { + return Collections.joinList(this, separator); + } - Collection filter(bool f(Node element)) => - Collections.filter(this, [], f); + List mappedBy(f(Node element)) => + new MappedList(this, f); + + Iterable where(bool f(Node element)) => + new WhereIterable(this, f); bool every(bool f(Node element)) => Collections.every(this, f); - bool some(bool f(Node element)) => Collections.some(this, f); + bool any(bool f(Node element)) => Collections.any(this, f); bool get isEmpty => this.length == 0; // From List: + List take(int n) { + return new ListView(this, 0, n); + } + + Iterable takeWhile(bool test(Node value)) { + return new TakeWhileIterable(this, test); + } + + List skip(int n) { + return new ListView(this, n, null); + } + + Iterable skipWhile(bool test(Node value)) { + return new SkipWhileIterable(this, test); + } + + Node firstMatching(bool test(Node value), {Node orElse()}) { + return Collections.firstMatching(this, test, orElse); + } + + Node lastMatching(bool test(Node value), {Node orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + Node singleMatching(bool test(Node value)) { + return Collections.singleMatching(this, test); + } + + Node elementAt(int index) { + return this[index]; + } + // TODO(jacobr): this could be implemented for child node lists. // The exception we throw here is misleading. void sort([int compare(Node a, Node b)]) { diff --git a/tools/dom/templates/html/impl/impl_Storage.darttemplate b/tools/dom/templates/html/impl/impl_Storage.darttemplate index a48e3da0479..d200bb8d112 100644 --- a/tools/dom/templates/html/impl/impl_Storage.darttemplate +++ b/tools/dom/templates/html/impl/impl_Storage.darttemplate @@ -8,7 +8,7 @@ part of html; class $CLASSNAME$EXTENDS implements Map $NATIVESPEC { // TODO(nweiz): update this when maps support lazy iteration - bool containsValue(String value) => values.some((e) => e == value); + bool containsValue(String value) => values.any((e) => e == value); bool containsKey(String key) => $dom_getItem(key) != null; diff --git a/tools/dom/templates/immutable_list_mixin.darttemplate b/tools/dom/templates/immutable_list_mixin.darttemplate index 0728c244148..f94ba1ca29f 100644 --- a/tools/dom/templates/immutable_list_mixin.darttemplate +++ b/tools/dom/templates/immutable_list_mixin.darttemplate @@ -3,31 +3,17 @@ // From Iterable<$E>: - Iterator<$E> iterator() { + Iterator<$E> get iterator { // Note: NodeLists are not fixed size. And most probably length shouldn't // be cached in both iterator _and_ forEach method. For now caching it // for consistency. return new FixedSizeListIterator<$E>(this); } - // From Collection<$E>: $if DEFINE_LENGTH_AS_NUM_ITEMS // SVG Collections expose numberOfItems rather than length. int get length => numberOfItems; $endif - - void add($E value) { - throw new UnsupportedError("Cannot add to immutable List."); - } - - void addLast($E value) { - throw new UnsupportedError("Cannot add to immutable List."); - } - - void addAll(Collection<$E> collection) { - throw new UnsupportedError("Cannot add to immutable List."); - } - dynamic reduce(dynamic initialValue, dynamic combine(dynamic, $E)) { return Collections.reduce(this, initialValue, combine); } @@ -40,17 +26,60 @@ $endif void forEach(void f($E element)) => Collections.forEach(this, f); - Collection map(f($E element)) => Collections.map(this, [], f); + String join([String separator]) => Collections.joinList(this, separator); - Collection<$E> filter(bool f($E element)) => - Collections.filter(this, <$E>[], f); + List mappedBy(f($E element)) => new MappedList<$E, dynamic>(this, f); + + Iterable<$E> where(bool f($E element)) => new WhereIterable<$E>(this, f); bool every(bool f($E element)) => Collections.every(this, f); - bool some(bool f($E element)) => Collections.some(this, f); + bool any(bool f($E element)) => Collections.any(this, f); bool get isEmpty => this.length == 0; + List<$E> take(int n) => new ListView<$E>(this, 0, n); + + Iterable<$E> takeWhile(bool test($E value)) { + return new TakeWhileIterable<$E>(this, test); + } + + List<$E> skip(int n) => new ListView<$E>(this, n, null); + + Iterable<$E> skipWhile(bool test($E value)) { + return new SkipWhileIterable<$E>(this, test); + } + + $E firstMatching(bool test($E value), { $E orElse() }) { + return Collections.firstMatching(this, test, orElse); + } + + $E lastMatching(bool test($E value), {$E orElse()}) { + return Collections.lastMatchingInList(this, test, orElse); + } + + $E singleMatching(bool test($E value)) { + return Collections.singleMatching(this, test); + } + + $E elementAt(int index) { + return this[index]; + } + + // From Collection<$E>: + + void add($E value) { + throw new UnsupportedError("Cannot add to immutable List."); + } + + void addLast($E value) { + throw new UnsupportedError("Cannot add to immutable List."); + } + + void addAll(Iterable<$E> iterable) { + throw new UnsupportedError("Cannot add to immutable List."); + } + // From List<$E>: $if DEFINE_LENGTH_SETTER void set length(int value) { @@ -78,9 +107,25 @@ $endif return Lists.lastIndexOf(this, element, start); } - $E get first => this[0]; + $E get first { + if (this.length > 0) return this[0]; + throw new StateError("No elements"); + } - $E get last => this[length - 1]; + $E get last { + if (this.length > 0) return this[this.length - 1]; + throw new StateError("No elements"); + } + + $E get single { + if (length == 1) return this[0]; + if (length == 0) throw new StateError("No elements"); + throw new StateError("More than one element"); + } + + $E min([int compare($E a, $E b)]) => _Collections.minInList(this, compare); + + $E max([int compare($E a, $E b)]) => _Collections.maxInList(this, compare); $E removeAt(int pos) { throw new UnsupportedError("Cannot removeAt on immutable List."); diff --git a/tools/html_json_doc/lib/json_to_html.dart b/tools/html_json_doc/lib/json_to_html.dart index d25aa4d0b7e..391cd3c1d6d 100644 --- a/tools/html_json_doc/lib/json_to_html.dart +++ b/tools/html_json_doc/lib/json_to_html.dart @@ -7,7 +7,7 @@ * the HTML files the comments are associated with. * * The format of the JSON file is: - * + * * { * "$filename": * { @@ -22,9 +22,9 @@ */ library json_to_html; -import 'dart:json'; +import 'dart:json' as JSON; import 'dart:io'; - +import 'dart:async'; /// True if any errors were triggered through the conversion. bool _anyErrors = false; @@ -139,7 +139,7 @@ void _convertFile(File file, Map> comments) { '${new Path(file.fullPathSync()).filename}:\n"$key"'); _anyErrors = true; }); - + // TODO(amouravski): file.writeAsStringSync('${Strings.join(fileLines, '\n')}\n'); var outputStream = file.openOutputStream(); outputStream.writeString(Strings.join(fileLines, '\n')); diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart index 8f9232b4b66..40d75c51a05 100644 --- a/tools/testing/dart/test_options.dart +++ b/tools/testing/dart/test_options.dart @@ -5,7 +5,6 @@ library test_options_parser; import "dart:io"; -import "dart:math"; import "drt_updater.dart"; import "test_suite.dart"; @@ -149,7 +148,7 @@ is 'dart file.dart' and you specify special command 'Progress indication mode', ['-p', '--progress'], ['compact', 'color', 'line', 'verbose', - 'silent', 'status', 'buildbot'], + 'silent', 'status', 'buildbot', 'diff'], 'compact'), new _TestOptionSpecification( 'step_name', @@ -368,7 +367,7 @@ Note: currently only implemented for dart2js.''', configuration[spec.name] = true; } else if (spec.type == 'int') { try { - configuration[spec.name] = parseInt(value); + configuration[spec.name] = int.parse(value); } catch (e) { print('Integer value expected for int option $name'); exit(1); diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart index 3ccc3eedab0..9cdcd56a10c 100644 --- a/tools/testing/dart/test_runner.dart +++ b/tools/testing/dart/test_runner.dart @@ -1672,7 +1672,7 @@ class ProcessQueue { var compiler = test.configuration['compiler']; var runners = _batchProcesses[compiler]; if (runners == null) { - runners = new List(_maxProcesses); + runners = new List.fixedLength(_maxProcesses); for (int i = 0; i < _maxProcesses; i++) { runners[i] = new BatchRunnerProcess(test); } diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart index 019812ac988..0fd572c8bf4 100644 --- a/utils/apidoc/apidoc.dart +++ b/utils/apidoc/apidoc.dart @@ -14,8 +14,9 @@ */ library apidoc; +import 'dart:async'; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; import 'html_diff.dart'; // TODO(rnystrom): Use "package:" URL (#4968). import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart'; @@ -87,7 +88,7 @@ void main() { print('Parsing MDN data...'); final mdnFile = new File.fromPath(doc.scriptDir.append('mdn/database.json')); - final mdn = JSON.parse(mdnFile.readAsStringSync()); + final mdn = json.parse(mdnFile.readAsStringSync()); print('Cross-referencing dart:html...'); HtmlDiff.initialize(libPath); @@ -484,7 +485,10 @@ class Apidoc extends doc.Dartdoc { // Use the corresponding DOM type when searching MDN. // TODO(rnystrom): Shame there isn't a simpler way to get the one item // out of a singleton Set. - typeString = domTypes.iterator().next(); + // TODO(floitsch): switch to domTypes.first, once that's implemented. + var iter = domTypes.iterator; + iter.moveNext(); + typeString = iter.current; } else { // Not a DOM type. return null; @@ -518,7 +522,10 @@ class Apidoc extends doc.Dartdoc { // Use the corresponding DOM member when searching MDN. // TODO(rnystrom): Shame there isn't a simpler way to get the one item // out of a singleton Set. - memberString = domMembers.iterator().next(); + // TODO(floitsch): switch to domTypes.first, once that's implemented. + var iter = domMembers.iterator; + iter.moveNext(); + memberString = iter.current; } else { // Not a DOM type. return null; diff --git a/utils/apidoc/mdn/extract.dart b/utils/apidoc/mdn/extract.dart index 4a371549956..d9622b5e05b 100644 --- a/utils/apidoc/mdn/extract.dart +++ b/utils/apidoc/mdn/extract.dart @@ -1,5 +1,5 @@ import 'dart:html'; -import 'dart:json'; +import 'dart:json' as json; // Workaround for HTML lib missing feature. Range newRange() { @@ -341,8 +341,8 @@ bool isSkippable(Node n) { void onEnd() { // Hideous hack to send JSON back to JS. - String dbJson = JSON.stringify(dbEntry); - // workaround bug in JSON parser. + String dbJson = json.stringify(dbEntry); + // workaround bug in json.parse. dbJson = dbJson.replaceAll("ZDARTIUMDOESNTESCAPESLASHNJXXXX", "\\n"); // Use postMessage to end the JSON to JavaScript. TODO(jacobr): use a simple @@ -449,22 +449,24 @@ String genPrettyHtmlFromElement(Element e) { class PostOrderTraversalIterator implements Iterator { Node _next; + Node _current; PostOrderTraversalIterator(Node start) { _next = _leftMostDescendent(start); } + Node get current => _current; bool get hasNext => _next != null; - Node next() { - if (_next == null) return null; - final ret = _next; + bool moveNext() { + _current = _next; + if (_next == null) return false; if (_next.nextNode != null) { _next = _leftMostDescendent(_next.nextNode); } else { _next = _next.parent; } - return ret; + return true; } static Node _leftMostDescendent(Node n) { @@ -475,11 +477,11 @@ class PostOrderTraversalIterator implements Iterator { } } -class PostOrderTraversal implements Iterable { +class PostOrderTraversal extends Iterable { final Node _node; PostOrderTraversal(this._node); - Iterator iterator() => new PostOrderTraversalIterator(_node); + Iterator get iterator => new PostOrderTraversalIterator(_node); } /** @@ -746,7 +748,7 @@ void scrapeSection(Element root, String sectionSelector, String currentType, // Figure out which column in the table contains member names by // tracking how many member names each column contains. - final numMatches = new List(i); + final numMatches = new List.fixedLength(i); for (int j = 0; j < i; j++) { numMatches[j] = 0; } @@ -961,7 +963,7 @@ void markRemoved(var e) { } } -// TODO(jacobr): remove this when the dartium JSON parser handles \n correctly. +// TODO(jacobr): remove this when the dartium JSON parse handles \n correctly. String JSONFIXUPHACK(String value) { return value.replaceAll("\n", "ZDARTIUMDOESNTESCAPESLASHNJXXXX"); } @@ -1307,7 +1309,7 @@ void main() { void documentLoaded(event) { // Load the database of expected methods and properties with an HttpRequest. new HttpRequest.get('${window.location}.json', (req) { - data = JSON.parse(req.responseText); + data = json.parse(req.responseText); dbEntry = {'members': [], 'srcUrl': pageUrl}; run(); }); diff --git a/utils/apidoc/mdn/postProcess.dart b/utils/apidoc/mdn/postProcess.dart index d70cf742588..801e7d1c56f 100644 --- a/utils/apidoc/mdn/postProcess.dart +++ b/utils/apidoc/mdn/postProcess.dart @@ -7,12 +7,12 @@ library postProcess; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; import 'util.dart'; void main() { // Database of code documentation. - Map database = JSON.parse( + Map database = json.parse( new File('output/database.json').readAsStringSync()); final filteredDb = {}; final obsolete = []; @@ -33,6 +33,6 @@ void main() { } } } - writeFileSync("output/database.filtered.json", JSON.stringify(filteredDb)); - writeFileSync("output/obsolete.json", JSON.stringify(obsolete)); + writeFileSync("output/database.filtered.json", json.stringify(filteredDb)); + writeFileSync("output/obsolete.json", json.stringify(obsolete)); } diff --git a/utils/apidoc/mdn/prettyPrint.dart b/utils/apidoc/mdn/prettyPrint.dart index d0a413cf849..6d4c323d853 100644 --- a/utils/apidoc/mdn/prettyPrint.dart +++ b/utils/apidoc/mdn/prettyPrint.dart @@ -5,14 +5,14 @@ library prettyPrint; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; import 'util.dart'; String orEmpty(String str) { return str == null ? "" : str; } -List sortStringCollection(Collection collection) { +List sortStringCollection(Iterable collection) { final out = []; out.addAll(collection); out.sort((String a, String b) => a.compareTo(b)); @@ -51,7 +51,7 @@ int addMissing(StringBuffer sb, String type, Map members) { void main() { // Database of code documentation. - final Map database = JSON.parse( + final Map database = json.parse( new File('output/database.filtered.json').readAsStringSync()); // Types we have documentation for. diff --git a/utils/apidoc/mdn/util.dart b/utils/apidoc/mdn/util.dart index 69a4c6ca2d0..b3389887a4d 100644 --- a/utils/apidoc/mdn/util.dart +++ b/utils/apidoc/mdn/util.dart @@ -1,14 +1,14 @@ library util; import 'dart:io'; -import 'dart:json'; +import 'dart:json' as json; Map _allProps; Map get allProps { if (_allProps == null) { // Database of expected property names for each type in WebKit. - _allProps = JSON.parse( + _allProps = parse.parse( new File('data/dartIdl.json').readAsStringSync()); } return _allProps; diff --git a/utils/archive/entry.dart b/utils/archive/entry.dart index d27bf49128f..41040c921c2 100644 --- a/utils/archive/entry.dart +++ b/utils/archive/entry.dart @@ -50,7 +50,7 @@ class ArchiveEntry { /** Create a new [ArchiveEntry] with default values for all of its fields. */ static Future create() { - return call(NEW).transform((properties) { + return call(NEW).then((properties) { return new archive.ArchiveEntry.internal(properties, null); }); } @@ -215,7 +215,7 @@ class ArchiveEntry { stream.onClosed = () => completer.complete(buffer); return Futures.wait([call(CLONE, _id), completer.future]) - .transform((list) => new CompleteArchiveEntry._(list[0], list[1])); + .then((list) => new CompleteArchiveEntry._(list[0], list[1])); } /** @@ -277,7 +277,7 @@ class ArchiveEntry { // Asynchronously complete to give the InputStream callbacks a chance to // fire. return async(); - }).transform((_) => inputCompleter.complete(null)); + }).then((_) => inputCompleter.complete(null)); future.handleException((e) { print(e); diff --git a/utils/archive/options.dart b/utils/archive/options.dart index 0eba56065fe..cfebf1fe1ac 100644 --- a/utils/archive/options.dart +++ b/utils/archive/options.dart @@ -48,5 +48,5 @@ class ArchiveOptions { } /** Gets all options. */ - List get all => _options.values; + List get all => _options.values.toList(); } diff --git a/utils/archive/reader.dart b/utils/archive/reader.dart index 04fdddffc9f..74760a53e98 100644 --- a/utils/archive/reader.dart +++ b/utils/archive/reader.dart @@ -60,7 +60,7 @@ class ArchiveReader { return _createArchive().chain((_id) { id = _id; return call(OPEN_FILENAME, id, [file, block_size]); - }).transform((_) => new ArchiveInputStream(id)); + }).then((_) => new ArchiveInputStream(id)); } /** Begins extracting from [data], which should be a list of bytes. */ @@ -69,7 +69,7 @@ class ArchiveReader { return _createArchive().chain((_id) { id = _id; return call(OPEN_MEMORY, id, [bytesForC(data)]); - }).transform((_) => new ArchiveInputStream(id)); + }).then((_) => new ArchiveInputStream(id)); } /** @@ -81,7 +81,7 @@ class ArchiveReader { if (id == 0 || id == null) { throw new ArchiveException("Archive is invalid or closed."); } - return _pushConfiguration(id).transform((_) => id); + return _pushConfiguration(id).then((_) => id); }); } diff --git a/utils/archive/utils.dart b/utils/archive/utils.dart index 1a0fc387cf1..a5e021995ec 100644 --- a/utils/archive/utils.dart +++ b/utils/archive/utils.dart @@ -33,7 +33,7 @@ SendPort _newServicePort() native "Archive_ServicePort"; Future call(int requestType, [int id, List args]) { var fullArgs = [requestType, id]; if (args != null) fullArgs.addAll(args); - return servicePort.call(listForC(fullArgs)).transform((response) { + return servicePort.call(listForC(fullArgs)).then((response) { var success = response[0]; var errno = response[1]; var message = response[2]; @@ -45,7 +45,7 @@ Future call(int requestType, [int id, List args]) { /** Converts [input] to a fixed-length list which C can understand. */ List listForC(List input) { - var list = new List(input.length); + var list = new List.fixedLength(input.length); list.setRange(0, input.length, input); return list; } diff --git a/utils/css/parser.dart b/utils/css/parser.dart index 37d11a584ab..4e0c1876147 100644 --- a/utils/css/parser.dart +++ b/utils/css/parser.dart @@ -37,7 +37,7 @@ class Parser { // } //
...
// } - // + // Stylesheet parse([bool nestedCSS = false, var erroMsgRedirector = null]) { // TODO(terry): Hack for migrating CSS errors back to template errors. _erroMsgRedirector = erroMsgRedirector; @@ -199,7 +199,7 @@ class Parser { /////////////////////////////////////////////////////////////////// // Productions /////////////////////////////////////////////////////////////////// - + processMedia([bool oneRequired = false]) { List media = []; @@ -656,7 +656,7 @@ class Parser { if (TokenKind.isIdentifier(_peekToken.kind)) { var propertyIdent = identifier(); _eat(TokenKind.COLON); - + decl = new Declaration(propertyIdent, processExpr(), _makeSpan(start)); // Handle !important (prio) @@ -763,11 +763,11 @@ class Parser { break; case TokenKind.INTEGER: t = _next(); - value = Math.parseInt("${unary}${t.text}"); + value = int.parse("${unary}${t.text}"); break; case TokenKind.DOUBLE: t = _next(); - value = Math.parseDouble("${unary}${t.text}"); + value = double.parse("${unary}${t.text}"); break; case TokenKind.SINGLE_QUOTE: case TokenKind.DOUBLE_QUOTE: @@ -978,7 +978,7 @@ class Parser { if (!TokenKind.isIdentifier(tok.kind)) { _error('expected identifier, but found $tok', tok.span); } - + return new Identifier(tok.text, _makeSpan(tok.start)); } diff --git a/utils/lib/file_system_vm.dart b/utils/lib/file_system_vm.dart index 12fb712873d..cc0c05c582b 100644 --- a/utils/lib/file_system_vm.dart +++ b/utils/lib/file_system_vm.dart @@ -20,7 +20,7 @@ class VMFileSystem implements FileSystem { String readAll(String filename) { var file = (new File(filename)).openSync(); var length = file.lengthSync(); - var buffer = new List(length); + var buffer = new List.fixedLength(length); var bytes = file.readListSync(buffer, 0, length); file.closeSync(); return new String.fromCharCodes(new Utf8Decoder(buffer).decodeRest()); diff --git a/utils/peg/pegparser.dart b/utils/peg/pegparser.dart index dd49d0aac22..13336825e4a 100644 --- a/utils/peg/pegparser.dart +++ b/utils/peg/pegparser.dart @@ -69,7 +69,7 @@ _Rule CHAR([characters]) { if (lo == hi) return CHARCODE(lo); int len = hi - lo + 1; - var flags = new List(len); + var flags = new List.fixedLength(len); for (int i = 0; i < len; ++i) flags[i] = false; for (int code in codes) diff --git a/utils/pub/command_install.dart b/utils/pub/command_install.dart index 2263755488c..001ba21cecf 100644 --- a/utils/pub/command_install.dart +++ b/utils/pub/command_install.dart @@ -4,6 +4,8 @@ library command_install; +import 'dart:async'; + import 'entrypoint.dart'; import 'log.dart' as log; import 'pub.dart'; @@ -14,7 +16,7 @@ class InstallCommand extends PubCommand { String get usage => "pub install"; Future onRun() { - return entrypoint.installDependencies().transform((_) { + return entrypoint.installDependencies().then((_) { log.message("Dependencies installed!"); }); } diff --git a/utils/pub/command_lish.dart b/utils/pub/command_lish.dart index 5afe32ff149..01136fdaaf2 100644 --- a/utils/pub/command_lish.dart +++ b/utils/pub/command_lish.dart @@ -63,12 +63,12 @@ class LishCommand extends PubCommand { request.files.add(new http.MultipartFile.fromBytes( 'file', packageBytes, filename: 'package.tar.gz')); return client.send(request); - }).chain(http.Response.fromStream).transform((response) { + }).chain(http.Response.fromStream).then((response) { var location = response.headers['location']; if (location == null) throw new PubHttpException(response); return location; - }).chain((location) => client.get(location)) - .transform(handleJsonSuccess); + }).then((location) => client.get(location)) + .then(handleJsonSuccess); }).transformException((e) { if (e is! PubHttpException) throw e; var url = e.response.request.url; @@ -126,8 +126,8 @@ class LishCommand extends PubCommand { } return listDir(rootDir, recursive: true).chain((entries) { - return Futures.wait(entries.map((entry) { - return fileExists(entry).transform((isFile) { + return Futures.wait(entries.mappedBy((entry) { + return fileExists(entry).then((isFile) { // Skip directories. if (!isFile) return null; @@ -140,13 +140,13 @@ class LishCommand extends PubCommand { }); })); }); - }).transform((files) => files.filter((file) { + }).then((files) => files.where((file) { if (file == null || _BLACKLISTED_FILES.contains(basename(file))) { return false; } return !splitPath(file).some(_BLACKLISTED_DIRECTORIES.contains); - })); + }).toList()); } /// Returns the value associated with [key] in [map]. Throws a user-friendly @@ -176,7 +176,7 @@ class LishCommand extends PubCommand { message = "Package has ${warnings.length} warning$s. Upload anyway"; } - return confirm(message).transform((confirmed) { + return confirm(message).then((confirmed) { if (!confirmed) throw "Package upload canceled."; }); }); diff --git a/utils/pub/command_update.dart b/utils/pub/command_update.dart index 1dda303e7cc..4757049cd26 100644 --- a/utils/pub/command_update.dart +++ b/utils/pub/command_update.dart @@ -4,6 +4,7 @@ library command_update; +import 'dart:async'; import 'entrypoint.dart'; import 'log.dart' as log; import 'pub.dart'; @@ -22,6 +23,6 @@ class UpdateCommand extends PubCommand { } else { future = entrypoint.updateDependencies(commandOptions.rest); } - return future.transform((_) => log.message("Dependencies updated!")); + return future.then((_) => log.message("Dependencies updated!")); } } diff --git a/utils/pub/curl_client.dart b/utils/pub/curl_client.dart index 6922b828e0b..7361b09abfc 100644 --- a/utils/pub/curl_client.dart +++ b/utils/pub/curl_client.dart @@ -4,6 +4,7 @@ library curl_client; +import 'dart:async'; import 'dart:io'; import '../../pkg/http/lib/http.dart' as http; @@ -39,7 +40,7 @@ class CurlClient extends http.BaseClient { var arguments = _argumentsForRequest(request, headerFile); log.process(executable, arguments); var process; - return startProcess(executable, arguments).chain((process_) { + return startProcess(executable, arguments).then((process_) { process = process_; if (requestStream.closed) { process.stdin.close(); @@ -48,8 +49,8 @@ class CurlClient extends http.BaseClient { } return _waitForHeaders(process, expectBody: request.method != "HEAD"); - }).chain((_) => new File(headerFile).readAsLines()) - .transform((lines) => _buildResponse(request, process, lines)); + }).then((_) => new File(headerFile).readAsLines()) + .then((lines) => _buildResponse(request, process, lines)); }); } @@ -126,7 +127,7 @@ class CurlClient extends http.BaseClient { } chainToCompleter(consumeInputStream(process.stderr) - .transform((stderrBytes) { + .then((stderrBytes) { var message = new String.fromCharCodes(stderrBytes); log.fine('Got error reading headers from curl: $message'); if (exitCode == 47) { diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart index b52a139ed67..457d480f687 100644 --- a/utils/pub/entrypoint.dart +++ b/utils/pub/entrypoint.dart @@ -4,6 +4,7 @@ library entrypoint; +import 'dart:async'; import 'io.dart'; import 'lock_file.dart'; import 'log.dart' as log; @@ -46,7 +47,7 @@ class Entrypoint { /// Loads the entrypoint from a package at [rootDir]. static Future load(String rootDir, SystemCache cache) { - return Package.load(null, rootDir, cache.sources).transform((package) => + return Package.load(null, rootDir, cache.sources).then((package) => new Entrypoint(package, cache)); } @@ -70,26 +71,26 @@ class Entrypoint { if (pendingOrCompleted != null) return pendingOrCompleted; var packageDir = join(path, id.name); - var future = ensureDir(dirname(packageDir)).chain((_) { + var future = ensureDir(dirname(packageDir)).then((_) { return exists(packageDir); - }).chain((exists) { + }).then((exists) { if (!exists) return new Future.immediate(null); // TODO(nweiz): figure out when to actually delete the directory, and when // we can just re-use the existing symlink. log.fine("Deleting package directory for ${id.name} before install."); return deleteDir(packageDir); - }).chain((_) { + }).then((_) { if (id.source.shouldCache) { - return cache.install(id).chain( + return cache.install(id).then( (pkg) => createPackageSymlink(id.name, pkg.dir, packageDir)); } else { - return id.source.install(id, packageDir).transform((found) { + return id.source.install(id, packageDir).then((found) { if (found) return null; // TODO(nweiz): More robust error-handling. throw 'Package ${id.name} not found in source "${id.source.name}".'; }); } - }).chain((_) => id.resolved); + }).then((_) => id.resolved); _installs[id] = future; @@ -101,8 +102,8 @@ class Entrypoint { /// completes when all dependencies are installed. Future installDependencies() { return loadLockFile() - .chain((lockFile) => resolveVersions(cache.sources, root, lockFile)) - .chain(_installDependencies); + .then((lockFile) => resolveVersions(cache.sources, root, lockFile)) + .then(_installDependencies); } /// Installs the latest available versions of all dependencies of the [root] @@ -110,33 +111,33 @@ class Entrypoint { /// [Future] that completes when all dependencies are installed. Future updateAllDependencies() { return resolveVersions(cache.sources, root, new LockFile.empty()) - .chain(_installDependencies); + .then(_installDependencies); } /// Installs the latest available versions of [dependencies], while leaving /// other dependencies as specified by the [LockFile] if possible. Returns a /// [Future] that completes when all dependencies are installed. Future updateDependencies(List dependencies) { - return loadLockFile().chain((lockFile) { + return loadLockFile().then((lockFile) { var versionSolver = new VersionSolver(cache.sources, root, lockFile); for (var dependency in dependencies) { versionSolver.useLatestVersion(dependency); } return versionSolver.solve(); - }).chain(_installDependencies); + }).then(_installDependencies); } /// Removes the old packages directory, installs all dependencies listed in /// [packageVersions], and writes a [LockFile]. Future _installDependencies(List packageVersions) { - return cleanDir(path).chain((_) { - return Futures.wait(packageVersions.map((id) { + return cleanDir(path).then((_) { + return Futures.wait(packageVersions.mappedBy((id) { if (id.source is RootSource) return new Future.immediate(id); return install(id); })); - }).chain(_saveLockFile) - .chain(_installSelfReference) - .chain(_linkSecondaryPackageDirs); + }).then(_saveLockFile) + .then(_installSelfReference) + .then(_linkSecondaryPackageDirs); } /// Loads the list of concrete package versions from the `pubspec.lock`, if it @@ -145,13 +146,13 @@ class Entrypoint { var lockFilePath = join(root.dir, 'pubspec.lock'); log.fine("Loading lockfile."); - return fileExists(lockFilePath).chain((exists) { + return fileExists(lockFilePath).then((exists) { if (!exists) { log.fine("No lock file at $lockFilePath, creating empty one."); return new Future.immediate(new LockFile.empty()); } - return readTextFile(lockFilePath).transform((text) => + return readTextFile(lockFilePath).then((text) => new LockFile.parse(text, cache.sources)); }); } @@ -172,10 +173,10 @@ class Entrypoint { /// allow a package to import its own files using `package:`. Future _installSelfReference(_) { var linkPath = join(path, root.name); - return exists(linkPath).chain((exists) { + return exists(linkPath).then((exists) { // Create the symlink if it doesn't exist. if (exists) return new Future.immediate(null); - return ensureDir(path).chain( + return ensureDir(path).then( (_) => createPackageSymlink(root.name, root.dir, linkPath, isSelfLink: true)); }); @@ -190,25 +191,25 @@ class Entrypoint { var testDir = join(root.dir, 'test'); var toolDir = join(root.dir, 'tool'); var webDir = join(root.dir, 'web'); - return dirExists(binDir).chain((exists) { + return dirExists(binDir).then((exists) { if (!exists) return new Future.immediate(null); return _linkSecondaryPackageDir(binDir); - }).chain((_) => _linkSecondaryPackageDirsRecursively(exampleDir)) - .chain((_) => _linkSecondaryPackageDirsRecursively(testDir)) - .chain((_) => _linkSecondaryPackageDirsRecursively(toolDir)) - .chain((_) => _linkSecondaryPackageDirsRecursively(webDir)); + }).then((_) => _linkSecondaryPackageDirsRecursively(exampleDir)) + .then((_) => _linkSecondaryPackageDirsRecursively(testDir)) + .then((_) => _linkSecondaryPackageDirsRecursively(toolDir)) + .then((_) => _linkSecondaryPackageDirsRecursively(webDir)); } /// Creates a symlink to the `packages` directory in [dir] and all its /// subdirectories. Future _linkSecondaryPackageDirsRecursively(String dir) { - return dirExists(dir).chain((exists) { + return dirExists(dir).then((exists) { if (!exists) return new Future.immediate(null); return _linkSecondaryPackageDir(dir) - .chain((_) => _listDirWithoutPackages(dir)) - .chain((files) { - return Futures.wait(files.map((file) { - return dirExists(file).chain((isDir) { + .then((_) => _listDirWithoutPackages(dir)) + .then((files) { + return Futures.wait(files.mappedBy((file) { + return dirExists(file).then((isDir) { if (!isDir) return new Future.immediate(null); return _linkSecondaryPackageDir(file); }); @@ -221,25 +222,25 @@ class Entrypoint { /// Recursively lists the contents of [dir], excluding hidden `.DS_Store` /// files and `package` files. Future> _listDirWithoutPackages(dir) { - return listDir(dir).chain((files) { - return Futures.wait(files.map((file) { + return listDir(dir).then((files) { + return Futures.wait(files.mappedBy((file) { if (basename(file) == 'packages') return new Future.immediate([]); - return dirExists(file).chain((isDir) { + return dirExists(file).then((isDir) { if (!isDir) return new Future.immediate([]); return _listDirWithoutPackages(file); - }).transform((subfiles) { + }).then((subfiles) { var fileAndSubfiles = [file]; fileAndSubfiles.addAll(subfiles); return fileAndSubfiles; }); })); - }).transform(flatten); + }).then(flatten); } /// Creates a symlink to the `packages` directory in [dir] if none exists. Future _linkSecondaryPackageDir(String dir) { var to = join(dir, 'packages'); - return exists(to).chain((exists) { + return exists(to).then((exists) { if (exists) return new Future.immediate(null); return createSymlink(path, to); }); diff --git a/utils/pub/git.dart b/utils/pub/git.dart index b216735f64c..df2e8565c3a 100644 --- a/utils/pub/git.dart +++ b/utils/pub/git.dart @@ -5,6 +5,7 @@ /// Helper functionality for invoking Git. library git; +import 'dart:async'; import 'io.dart'; import 'log.dart' as log; import 'utils.dart'; @@ -14,18 +15,18 @@ Future get isInstalled { if (_isGitInstalledCache != null) { // TODO(rnystrom): The sleep is to pump the message queue. Can use // Future.immediate() when #3356 is fixed. - return sleep(0).transform((_) => _isGitInstalledCache); + return sleep(0).then((_) => _isGitInstalledCache); } - return _gitCommand.transform((git) => git != null); + return _gitCommand.then((git) => git != null); } /// Run a git process with [args] from [workingDir]. Returns the stdout as a /// list of strings if it succeeded. Completes to an exception if it failed. Future> run(List args, {String workingDir}) { - return _gitCommand.chain((git) { + return _gitCommand.then((git) { return runProcess(git, args, workingDir: workingDir); - }).transform((result) { + }).then((result) { if (!result.success) throw new Exception( 'Git error. Command: git ${Strings.join(args, " ")}\n' '${Strings.join(result.stderr, "\n")}'); @@ -44,18 +45,18 @@ String _gitCommandCache; Future get _gitCommand { // TODO(nweiz): Just use Future.immediate once issue 3356 is fixed. if (_gitCommandCache != null) { - return sleep(0).transform((_) => _gitCommandCache); + return sleep(0).then((_) => _gitCommandCache); } - return _tryGitCommand("git").chain((success) { + return _tryGitCommand("git").then((success) { if (success) return new Future.immediate("git"); // Git is sometimes installed on Windows as `git.cmd` - return _tryGitCommand("git.cmd").transform((success) { + return _tryGitCommand("git.cmd").then((success) { if (success) return "git.cmd"; return null; }); - }).transform((command) { + }).then((command) { log.fine('Determined git command $command.'); _gitCommandCache = command; return command; @@ -69,17 +70,16 @@ Future _tryGitCommand(String command) { // If "git --version" prints something familiar, git is working. var future = runProcess(command, ["--version"]); - future.then((results) { - var regex = new RegExp("^git version"); - completer.complete(results.stdout.length == 1 && - regex.hasMatch(results.stdout[0])); - }); - - future.handleException((err) { - // If the process failed, they probably don't have it. - completer.complete(false); - return true; - }); + future + .then((results) { + var regex = new RegExp("^git version"); + completer.complete(results.stdout.length == 1 && + regex.hasMatch(results.stdout[0])); + }) + .catchError((err) { + // If the process failed, they probably don't have it. + completer.complete(false); + }); return completer.future; } diff --git a/utils/pub/git_source.dart b/utils/pub/git_source.dart index e54b6cf1522..0a3e2b9721f 100644 --- a/utils/pub/git_source.dart +++ b/utils/pub/git_source.dart @@ -4,6 +4,7 @@ library git_source; +import 'dart:async'; import 'git.dart' as git; import 'io.dart'; import 'package.dart'; @@ -34,7 +35,7 @@ class GitSource extends Source { Future installToSystemCache(PackageId id) { var revisionCachePath; - return git.isInstalled.chain((installed) { + return git.isInstalled.then((installed) { if (!installed) { throw new Exception( "Cannot install '${id.name}' from Git (${_getUrl(id)}).\n" @@ -42,19 +43,19 @@ class GitSource extends Source { } return ensureDir(join(systemCacheRoot, 'cache')); - }).chain((_) => _ensureRepoCache(id)) - .chain((_) => _revisionCachePath(id)) - .chain((path) { + }).then((_) => _ensureRepoCache(id)) + .then((_) => _revisionCachePath(id)) + .then((path) { revisionCachePath = path; return exists(revisionCachePath); - }).chain((exists) { + }).then((exists) { if (exists) return new Future.immediate(null); return _clone(_repoCachePath(id), revisionCachePath, mirror: false); - }).chain((_) { + }).then((_) { var ref = _getEffectiveRef(id); if (ref == 'HEAD') return new Future.immediate(null); return _checkOut(revisionCachePath, ref); - }).chain((_) { + }).then((_) { return Package.load(id.name, revisionCachePath, systemCache.sources); }); } @@ -91,7 +92,7 @@ class GitSource extends Source { /// Attaches a specific commit to [id] to disambiguate it. Future resolveId(PackageId id) { - return _revisionAt(id).transform((revision) { + return _revisionAt(id).then((revision) { var description = {'url': _getUrl(id), 'ref': _getRef(id)}; description['resolved-ref'] = revision; return new PackageId(id.name, this, id.version, description); @@ -104,22 +105,22 @@ class GitSource extends Source { /// fails. Future _ensureRepoCache(PackageId id) { var path = _repoCachePath(id); - return exists(path).chain((exists) { + return exists(path).then((exists) { if (!exists) return _clone(_getUrl(id), path, mirror: true); - return git.run(["fetch"], workingDir: path).transform((result) => null); + return git.run(["fetch"], workingDir: path).then((result) => null); }); } /// Returns a future that completes to the revision hash of [id]. Future _revisionAt(PackageId id) { return git.run(["rev-parse", _getEffectiveRef(id)], - workingDir: _repoCachePath(id)).transform((result) => result[0]); + workingDir: _repoCachePath(id)).then((result) => result[0]); } /// Returns the path to the revision-specific cache of [id]. Future _revisionCachePath(PackageId id) { - return _revisionAt(id).transform((rev) { + return _revisionAt(id).then((rev) { var revisionCacheName = '${id.name}-$rev'; return join(systemCacheRoot, revisionCacheName); }); @@ -134,16 +135,16 @@ class GitSource extends Source { Future _clone(String from, String to, {bool mirror: false}) { // Git on Windows does not seem to automatically create the destination // directory. - return ensureDir(to).chain((_) { + return ensureDir(to).then((_) { var args = ["clone", from, to]; if (mirror) args.insertRange(1, 1, "--mirror"); return git.run(args); - }).transform((result) => null); + }).then((result) => null); } /// Checks out the reference [ref] in [repoPath]. Future _checkOut(String repoPath, String ref) { - return git.run(["checkout", ref], workingDir: repoPath).transform( + return git.run(["checkout", ref], workingDir: repoPath).then( (result) => null); } diff --git a/utils/pub/hosted_source.dart b/utils/pub/hosted_source.dart index 4b515aca4f2..45867e5f924 100644 --- a/utils/pub/hosted_source.dart +++ b/utils/pub/hosted_source.dart @@ -4,8 +4,9 @@ library hosted_source; +import 'dart:async'; import 'dart:io' as io; -import 'dart:json'; +import 'dart:json' as json; import 'dart:uri'; // TODO(nweiz): Make this import better. @@ -35,9 +36,11 @@ class HostedSource extends Source { var parsed = _parseDescription(description); var fullUrl = "${parsed.last}/packages/${parsed.first}.json"; - return httpClient.read(fullUrl).transform((body) { - var doc = JSON.parse(body); - return doc['versions'].map((version) => new Version.parse(version)); + return httpClient.read(fullUrl).then((body) { + var doc = json.parse(body); + return doc['versions'] + .mappedBy((version) => new Version.parse(version)) + .toList(); }).transformException((ex) { _throwFriendlyError(ex, parsed.first, parsed.last); }); @@ -50,7 +53,7 @@ class HostedSource extends Source { var fullUrl = "${parsed.last}/packages/${parsed.first}/versions/" "${id.version}.yaml"; - return httpClient.read(fullUrl).transform((yaml) { + return httpClient.read(fullUrl).then((yaml) { return new Pubspec.parse(yaml, systemCache.sources); }).transformException((ex) { _throwFriendlyError(ex, id, parsed.last); @@ -71,18 +74,18 @@ class HostedSource extends Source { var tempDir; return Futures.wait([ httpClient.send(new http.Request("GET", new Uri.fromString(fullUrl))) - .transform((response) => response.stream), + .then((response) => response.stream), systemCache.createTempDir() - ]).chain((args) { + ]).then((args) { tempDir = args[1]; return timeout(extractTarGz(args[0], tempDir), HTTP_TIMEOUT, 'fetching URL "$fullUrl"'); - }).chain((_) { + }).then((_) { // Now that the install has succeeded, move it to the real location in // the cache. This ensures that we don't leave half-busted ghost // directories in the user's pub cache if an install fails. return renameDir(tempDir, destPath); - }).transform((_) => true); + }).then((_) => true); } /// The system cache directory for the hosted source contains subdirectories diff --git a/utils/pub/io.dart b/utils/pub/io.dart index 8b53575ac7c..cc8902c3ac4 100644 --- a/utils/pub/io.dart +++ b/utils/pub/io.dart @@ -5,6 +5,7 @@ /// Helper functionality to make working with IO easier. library io; +import 'dart:async'; import 'dart:io'; import 'dart:isolate'; import 'dart:json'; @@ -26,7 +27,7 @@ final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); /// [File] objects. String join(part1, [part2, part3, part4, part5, part6, part7, part8]) { var parts = [part1, part2, part3, part4, part5, part6, part7, part8] - .map((part) => part == null ? null : _getPath(part)); + .mappedBy((part) => part == null ? null : _getPath(part)).toList(); return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7]); @@ -58,7 +59,7 @@ String relativeTo(target, base) => path.relative(target, from: base); /// completes with the result. Future exists(path) { path = _getPath(path); - return Futures.wait([fileExists(path), dirExists(path)]).transform((results) { + return Futures.wait([fileExists(path), dirExists(path)]).then((results) { return results[0] || results[1]; }); } @@ -103,9 +104,9 @@ Future writeTextFile(file, String contents, {dontLogContents: false}) { log.fine("Contents:\n$contents"); } - return file.open(FileMode.WRITE).chain((opened) { - return opened.writeString(contents).chain((ignore) { - return opened.close().transform((_) { + return file.open(FileMode.WRITE).then((opened) { + return opened.writeString(contents).then((ignore) { + return opened.close().then((_) { log.fine("Wrote text file $path."); return file; }); @@ -177,29 +178,25 @@ Future ensureDir(path) { log.fine("Ensuring directory $path exists."); if (path == '.') return new Future.immediate(new Directory('.')); - return dirExists(path).chain((exists) { + return dirExists(path).then((exists) { if (exists) { log.fine("Directory $path already exists."); return new Future.immediate(new Directory(path)); } - return ensureDir(dirname(path)).chain((_) { - var completer = new Completer(); - var future = createDir(path); - future.handleException((error) { - if (error is! DirectoryIOException) return false; - // Error 17 means the directory already exists (or 183 on Windows). - if (error.osError.errorCode != 17 && - error.osError.errorCode != 183) { + return ensureDir(dirname(path)).then((_) { + return createDir(path) + .catchError((error) { + if (error is! DirectoryIOException) return false; + // Error 17 means the directory already exists (or 183 on Windows). + if (error.osError.errorCode != 17 && + error.osError.errorCode != 183) { log.fine("Got 'already exists' error when creating directory."); return false; } - completer.complete(_getDirectory(path)); - return true; - }); - future.then(completer.complete); - return completer.future; + return _getDirectory(path); + }); }); }); } @@ -310,10 +307,10 @@ Future dirExists(dir) { /// new empty directory will be created. Returns a [Future] that completes when /// the new clean directory is created. Future cleanDir(dir) { - return dirExists(dir).chain((exists) { + return dirExists(dir).then((exists) { if (exists) { // Delete it first. - return deleteDir(dir).chain((_) => createDir(dir)); + return deleteDir(dir).then((_) => createDir(dir)); } else { // Just create it. return createDir(dir); @@ -327,7 +324,7 @@ Future renameDir(from, String to) { from = _getDirectory(from); log.io("Renaming directory ${from.path} to $to."); - return _attemptRetryable(() => from.rename(to)).transform((dir) { + return _attemptRetryable(() => from.rename(to)).then((dir) { log.fine("Renamed directory ${from.path} to $to."); return dir; }); @@ -385,7 +382,7 @@ Future createSymlink(from, to) { args = ['/j', to, from]; } - return runProcess(command, args).transform((result) { + return runProcess(command, args).then((result) { // TODO(rnystrom): Check exit code and output? return new File(to); }); @@ -400,7 +397,7 @@ Future createPackageSymlink(String name, from, to, {bool isSelfLink: false}) { // See if the package has a "lib" directory. from = join(from, 'lib'); - return dirExists(from).chain((exists) { + return dirExists(from).then((exists) { log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'."); if (exists) return createSymlink(from, to); @@ -582,7 +579,7 @@ InputStream wrapInputStream(InputStream source) { Future runProcess(String executable, List args, {workingDir, Map environment}) { return _doProcess(Process.run, executable, args, workingDir, environment) - .transform((result) { + .then((result) { // TODO(rnystrom): Remove this and change to returning one string. List toLines(String output) { var lines = output.split(NEWLINE_PATTERN); @@ -608,7 +605,7 @@ Future runProcess(String executable, List args, Future startProcess(String executable, List args, {workingDir, Map environment}) => _doProcess(Process.start, executable, args, workingDir, environment) - .transform((process) => new _WrappedProcess(process)); + .then((process) => new _WrappedProcess(process)); /// A wrapper around [Process] that buffers the stdout and stderr to avoid /// running into issue 7218. @@ -671,23 +668,24 @@ Future _doProcess(Function fn, String executable, List args, workingDir, /// Note that timing out will not cancel the asynchronous operation behind /// [input]. Future timeout(Future input, int milliseconds, String description) { + bool completed = false; var completer = new Completer(); var timer = new Timer(milliseconds, (_) { - if (completer.future.isComplete) return; - completer.completeException(new TimeoutException( + completer = true; + completer.completeError(new TimeoutException( 'Timed out while $description.')); }); - input.handleException((e) { - if (completer.future.isComplete) return false; - timer.cancel(); - completer.completeException(e, input.stackTrace); - return true; - }); - input.then((value) { - if (completer.future.isComplete) return; - timer.cancel(); - completer.complete(value); - }); + input + .then((value) { + if (completed) return; + timer.cancel(); + completer.complete(value); + }) + .catchError((e) { + if (completed) return; + timer.cancel(); + completer.completeError(e.error, e.stackTrace); + }); return completer.future; } @@ -696,11 +694,11 @@ Future timeout(Future input, int milliseconds, String description) { /// will be deleted. Future withTempDir(Future fn(String path)) { var tempDir; - var future = createTempDir().chain((dir) { + var future = createTempDir().then((dir) { tempDir = dir; return fn(tempDir.path); }); - future.onComplete((_) { + future.catchError((_) {}).then(_) { log.fine('Cleaning up temp directory ${tempDir.path}.'); deleteDir(tempDir); }); @@ -712,16 +710,16 @@ Future get isGitInstalled { if (_isGitInstalledCache != null) { // TODO(rnystrom): The sleep is to pump the message queue. Can use // Future.immediate() when #3356 is fixed. - return sleep(0).transform((_) => _isGitInstalledCache); + return sleep(0).then((_) => _isGitInstalledCache); } - return _gitCommand.transform((git) => git != null); + return _gitCommand.then((git) => git != null); } /// Run a git process with [args] from [workingDir]. Future runGit(List args, {String workingDir, Map environment}) { - return _gitCommand.chain((git) => runProcess(git, args, + return _gitCommand.then((git) => runProcess(git, args, workingDir: workingDir, environment: environment)); } @@ -730,18 +728,18 @@ Future runGit(List args, Future get _gitCommand { // TODO(nweiz): Just use Future.immediate once issue 3356 is fixed. if (_gitCommandCache != null) { - return sleep(0).transform((_) => _gitCommandCache); + return sleep(0).then((_) => _gitCommandCache); } - return _tryGitCommand("git").chain((success) { + return _tryGitCommand("git").then((success) { if (success) return new Future.immediate("git"); // Git is sometimes installed on Windows as `git.cmd` - return _tryGitCommand("git.cmd").transform((success) { + return _tryGitCommand("git.cmd").then((success) { if (success) return "git.cmd"; return null; }); - }).transform((command) { + }).then((command) { _gitCommandCache = command; return command; }); @@ -758,12 +756,9 @@ Future _tryGitCommand(String command) { var regex = new RegExp("^git version"); completer.complete(results.stdout.length == 1 && regex.hasMatch(results.stdout[0])); - }); - - future.handleException((err) { + }).catchError((err) { // If the process failed, they probably don't have it. completer.complete(false); - return true; }); return completer.future; @@ -788,13 +783,11 @@ Future extractTarGz(InputStream stream, destination) { stream.pipe(process.stdin); process.stdout.pipe(stdout, close: false); process.stderr.pipe(stderr, close: false); - }); - processFuture.handleException((error) { - completer.completeException(error, processFuture.stackTrace); - return true; + }).catchError((e) { + completer.completeError(e.error, e.stackTrace); }); - return completer.future.transform((exitCode) { + return completer.future.then((exitCode) { log.fine("Extracted .tar.gz stream to $destination. Exit code $exitCode."); // TODO(rnystrom): Does anything check this result value? If not, it should // throw on a bad exit code. @@ -818,17 +811,17 @@ Future _extractTarGzWindows(InputStream stream, String destination) { var tempDir; // TODO(rnystrom): Use withTempDir(). - return createTempDir().chain((temp) { + return createTempDir().then((temp) { // Write the archive to a temp file. tempDir = temp; return createFileFromStream(stream, join(tempDir, 'data.tar.gz')); - }).chain((_) { + }).then((_) { // 7zip can't unarchive from gzip -> tar -> destination all in one step // first we un-gzip it to a tar file. // Note: Setting the working directory instead of passing in a full file // path because 7zip says "A full path is not allowed here." return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir); - }).chain((result) { + }).then((result) { if (result.exitCode != 0) { throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n' '${Strings.join(result.stdout, "\n")}\n' @@ -836,7 +829,7 @@ Future _extractTarGzWindows(InputStream stream, String destination) { } // Find the tar file we just created since we don't know its name. return listDir(tempDir); - }).chain((files) { + }).then((files) { var tarFile; for (var file in files) { if (path.extension(file) == '.tar') { @@ -849,7 +842,7 @@ Future _extractTarGzWindows(InputStream stream, String destination) { // Untar the archive into the destination directory. return runProcess(command, ['x', tarFile], workingDir: destination); - }).chain((result) { + }).then((result) { if (result.exitCode != 0) { throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n' '${Strings.join(result.stdout, "\n")}\n' @@ -859,7 +852,7 @@ Future _extractTarGzWindows(InputStream stream, String destination) { log.fine('Clean up 7zip temp directory ${tempDir.path}.'); // TODO(rnystrom): Should also delete this if anything fails. return deleteDir(tempDir); - }).transform((_) => true); + }).then((_) => true); } /// Create a .tar.gz archive from a list of entries. Each entry can be a @@ -878,17 +871,17 @@ InputStream createTarGz(List contents, {baseDir}) { if (baseDir == null) baseDir = path.current; baseDir = getFullPath(baseDir); - contents = contents.map((entry) { + contents = contents.mappedBy((entry) { entry = getFullPath(entry); if (!isBeneath(entry, baseDir)) { throw 'Entry $entry is not inside $baseDir.'; } return relativeTo(entry, baseDir); - }); + }).toList(); if (Platform.operatingSystem != "windows") { var args = ["--create", "--gzip", "--directory", baseDir]; - args.addAll(contents.map(_getPath)); + args.addAll(contents.mappedBy(_getPath)); // TODO(nweiz): It's possible that enough command-line arguments will make // the process choke, so at some point we should save the arguments to a // file and pass them in via --files-from for tar and -i@filename for 7zip. @@ -908,7 +901,7 @@ InputStream createTarGz(List contents, {baseDir}) { // Create the tar file. var tarFile = join(tempDir, "intermediate.tar"); var args = ["a", "-w$baseDir", tarFile]; - args.addAll(contents.map((entry) => '-i!"$entry"')); + args.addAll(contents.mappedBy((entry) => '-i!"$entry"')); // Note: This line of code gets munged by create_sdk.py to be the correct // relative path to 7zip in the SDK. diff --git a/utils/pub/lock_file.dart b/utils/pub/lock_file.dart index 80036b84599..1e975852ff2 100644 --- a/utils/pub/lock_file.dart +++ b/utils/pub/lock_file.dart @@ -4,7 +4,7 @@ library lock_file; -import 'dart:json'; +import 'dart:json' as json; import 'package.dart'; import 'source_registry.dart'; import 'utils.dart'; @@ -85,6 +85,6 @@ class LockFile { // TODO(nweiz): Serialize using the YAML library once it supports // serialization. For now, we use JSON, since it's a subset of YAML anyway. - return JSON.stringify({'packages': packagesObj}); + return json.stringify({'packages': packagesObj}); } } diff --git a/utils/pub/log.dart b/utils/pub/log.dart index 029f72cf6e5..683c4a26165 100644 --- a/utils/pub/log.dart +++ b/utils/pub/log.dart @@ -97,7 +97,7 @@ Future ioAsync(String startMessage, Future operation, io(startMessage); } - return operation.transform((result) { + return operation.then((result) { if (endMessage == null) { io("End $startMessage."); } else { diff --git a/utils/pub/oauth2.dart b/utils/pub/oauth2.dart index 378614b3084..786ff35ee6e 100644 --- a/utils/pub/oauth2.dart +++ b/utils/pub/oauth2.dart @@ -108,7 +108,7 @@ Future _getClient(SystemCache cache) { return new Future.immediate(new Client( _identifier, _secret, credentials, httpClient: curlClient)); }).chain((client) { - return _saveCredentials(cache, client.credentials).transform((_) => client); + return _saveCredentials(cache, client.credentials).then((_) => client); }); } @@ -130,7 +130,7 @@ Future _loadCredentials(SystemCache cache) { return new Future.immediate(null); } - return readTextFile(_credentialsFile(cache)).transform((credentialsJson) { + return readTextFile(_credentialsFile(cache)).then((credentialsJson) { var credentials = new Credentials.fromJson(credentialsJson); if (credentials.isExpired && !credentials.canRefresh) { log.error("Pub's authorization to upload packages has expired and " @@ -194,7 +194,7 @@ Future _authorize() { response.headers.set('location', 'http://pub.dartlang.org/authorized'); response.outputStream.close(); return grant.handleAuthorizationResponse(queryToMap(queryString)); - }).transform((client) { + }).then((client) { server.close(); return client; }), completer); @@ -210,7 +210,7 @@ Future _authorize() { 'Then click "Allow access".\n\n' 'Waiting for your authorization...'); - return completer.future.transform((client) { + return completer.future.then((client) { log.message('Successfully authorized.\n'); return client; }); diff --git a/utils/pub/package.dart b/utils/pub/package.dart index 69b548341bc..70f469c0ea6 100644 --- a/utils/pub/package.dart +++ b/utils/pub/package.dart @@ -4,6 +4,7 @@ library package; +import 'dart:async'; import 'io.dart'; import 'pubspec.dart'; import 'source.dart'; @@ -19,10 +20,10 @@ class Package { SourceRegistry sources) { var pubspecPath = join(packageDir, 'pubspec.yaml'); - return fileExists(pubspecPath).chain((exists) { + return fileExists(pubspecPath).then((exists) { if (!exists) throw new PubspecNotFoundException(name); return readTextFile(pubspecPath); - }).transform((contents) { + }).then((contents) { try { var pubspec = new Pubspec.parse(contents, sources); diff --git a/utils/pub/pub.dart b/utils/pub/pub.dart index 6fcecd95885..1a8642e7bdb 100644 --- a/utils/pub/pub.dart +++ b/utils/pub/pub.dart @@ -5,6 +5,7 @@ /// The main entrypoint for the pub command line application. library pub; +import 'dart:async'; import '../../pkg/args/lib/args.dart'; import '../../pkg/path/lib/path.dart' as path; import 'dart:io'; @@ -244,7 +245,7 @@ abstract class PubCommand { future = Entrypoint.load(path.current, cache); } - future = future.chain((entrypoint) { + future = future.then((entrypoint) { this.entrypoint = entrypoint; try { var commandFuture = onRun(); @@ -257,23 +258,24 @@ abstract class PubCommand { } }); - future = future.chain((_) => cache_.deleteTempDir()); - future.handleException((e) { - if (e is PubspecNotFoundException && e.name == null) { - e = 'Could not find a file named "pubspec.yaml" in the directory ' - '${path.current}.'; - } else if (e is PubspecHasNoNameException && e.name == null) { - e = 'pubspec.yaml is missing the required "name" field (e.g. "name: ' - '${basename(path.current)}").'; - } + future + .then((_) => cache_.deleteTempDir()) + .catchError((error) { + var e = error.error; + if (e is PubspecNotFoundException && e.name == null) { + e = 'Could not find a file named "pubspec.yaml" in the directory ' + '${path.current}.'; + } else if (e is PubspecHasNoNameException && e.name == null) { + e = 'pubspec.yaml is missing the required "name" field (e.g. "name: ' + '${basename(path.current)}").'; + } - handleError(e, future.stackTrace); - }); - - // Explicitly exit on success to ensure that any dangling dart:io handles - // don't cause the process to never terminate. - future.then((_) => exit(0)); + handleError(e, error.stackTrace); + }) + // Explicitly exit on success to ensure that any dangling dart:io handles + // don't cause the process to never terminate. + .then((_) => exit(0)); } /// Override this to perform the specific command. Return a future that diff --git a/utils/pub/pubspec.dart b/utils/pub/pubspec.dart index 8a1931dc6f7..078b7e05dc8 100644 --- a/utils/pub/pubspec.dart +++ b/utils/pub/pubspec.dart @@ -133,7 +133,7 @@ List _parseDependencies(SourceRegistry sources, yaml) { // Allow an empty dependencies key. if (yaml == null) return dependencies; - if (yaml is! Map || yaml.keys.some((e) => e is! String)) { + if (yaml is! Map || yaml.keys.any((e) => e is! String)) { throw new FormatException( 'The pubspec dependencies should be a map of package names, but ' 'was ${yaml}.'); @@ -154,7 +154,7 @@ List _parseDependencies(SourceRegistry sources, yaml) { versionConstraint = new VersionConstraint.parse(spec.remove('version')); } - var sourceNames = spec.keys; + var sourceNames = spec.keys.toList(); if (sourceNames.length > 1) { throw new FormatException( 'Dependency $name may only have one source: $sourceNames.'); diff --git a/utils/pub/sdk_source.dart b/utils/pub/sdk_source.dart index 654043a266c..13ffa2525e9 100644 --- a/utils/pub/sdk_source.dart +++ b/utils/pub/sdk_source.dart @@ -4,6 +4,7 @@ library sdk_source; +import 'dart:async'; import 'io.dart'; import 'package.dart'; import 'pubspec.dart'; @@ -30,14 +31,14 @@ class SdkSource extends Source { /// inferred from the revision number of the SDK itself. Future describe(PackageId id) { var version; - return readTextFile(join(rootDir, "revision")).chain((revision) { + return readTextFile(join(rootDir, "revision")).then((revision) { version = new Version.parse("0.0.0-r.${revision.trim()}"); // Read the pubspec for the package's dependencies. return _getPackagePath(id); - }).chain((packageDir) { + }).then((packageDir) { // TODO(rnystrom): What if packageDir is null? return Package.load(id.name, packageDir, systemCache.sources); - }).transform((package) { + }).then((package) { // Ignore the pubspec's version, and use the SDK's. return new Pubspec(id.name, version, package.pubspec.dependencies); }); @@ -46,10 +47,10 @@ class SdkSource extends Source { /// Since all the SDK files are already available locally, installation just /// involves symlinking the SDK library into the packages directory. Future install(PackageId id, String destPath) { - return _getPackagePath(id).chain((path) { + return _getPackagePath(id).then((path) { if (path == null) return new Future.immediate(false); - return createPackageSymlink(id.name, path, destPath).transform( + return createPackageSymlink(id.name, path, destPath).then( (_) => true); }); } @@ -60,14 +61,14 @@ class SdkSource extends Source { Future _getPackagePath(PackageId id) { // Look in "pkg" first. var pkgPath = join(rootDir, "pkg", id.description); - return exists(pkgPath).chain((found) { + return exists(pkgPath).then((found) { if (found) return new Future.immediate(pkgPath); // Not in "pkg", so try "lib". // TODO(rnystrom): Get rid of this when all SDK packages are moved from // "lib" to "pkg". var libPath = join(rootDir, "lib", id.description); - return exists(libPath).transform((found) => found ? libPath : null); + return exists(libPath).then((found) => found ? libPath : null); }); } } diff --git a/utils/pub/source.dart b/utils/pub/source.dart index 637cdd6950d..211f0dbad4d 100644 --- a/utils/pub/source.dart +++ b/utils/pub/source.dart @@ -4,6 +4,7 @@ library source; +import 'dart:async'; import 'io.dart'; import 'package.dart'; import 'pubspec.dart'; @@ -64,7 +65,7 @@ abstract class Source { /// uses [describe] to get that version. Future> getVersions(String name, description) { return describe(new PackageId(name, this, Version.none, description)) - .transform((pubspec) => [pubspec.version]); + .then((pubspec) => [pubspec.version]); } /// Loads the (possibly remote) pubspec for the package version identified by @@ -76,7 +77,7 @@ abstract class Source { /// must implement it manually. Future describe(PackageId id) { if (!shouldCache) throw "Source $name must implement describe(id)."; - return installToSystemCache(id).transform((package) => package.pubspec); + return installToSystemCache(id).then((package) => package.pubspec); } /// Installs the package identified by [id] to [path]. Returns a [Future] that @@ -104,10 +105,10 @@ abstract class Source { /// By default, this uses [systemCacheDirectory] and [install]. Future installToSystemCache(PackageId id) { var path = systemCacheDirectory(id); - return exists(path).chain((exists) { + return exists(path).then((exists) { if (exists) return new Future.immediate(true); - return ensureDir(dirname(path)).chain((_) => install(id, path)); - }).chain((found) { + return ensureDir(dirname(path)).then((_) => install(id, path)); + }).then((found) { if (!found) throw 'Package $id not found.'; return Package.load(id.name, path, systemCache.sources); }); diff --git a/utils/pub/system_cache.dart b/utils/pub/system_cache.dart index abd23482441..5b00dc301b6 100644 --- a/utils/pub/system_cache.dart +++ b/utils/pub/system_cache.dart @@ -5,6 +5,7 @@ library system_cache; import 'dart:io'; +import 'dart:async'; import 'git_source.dart'; import 'hosted_source.dart'; @@ -83,7 +84,7 @@ class SystemCache { /// temp directory to ensure that it's on the same volume as the pub system /// cache so that it can move the directory from it. Future createTempDir() { - return ensureDir(tempDir).chain((temp) { + return ensureDir(tempDir).then((temp) { return io.createTempDir(join(temp, 'dir')); }); } @@ -91,7 +92,7 @@ class SystemCache { /// Delete's the system cache's internal temp directory. Future deleteTempDir() { log.fine('Clean up system cache temp directory $tempDir.'); - return dirExists(tempDir).chain((exists) { + return dirExists(tempDir).then((exists) { if (!exists) return new Future.immediate(null); return deleteDir(tempDir); }); diff --git a/utils/pub/utils.dart b/utils/pub/utils.dart index 557e67de027..b922d845d40 100644 --- a/utils/pub/utils.dart +++ b/utils/pub/utils.dart @@ -5,6 +5,7 @@ /// Generic utility functions. Stuff that should possibly be in core. library utils; +import 'dart:async'; import 'dart:crypto'; import 'dart:isolate'; import 'dart:uri'; @@ -42,17 +43,12 @@ String padRight(String source, int length) { /// Runs [fn] after [future] completes, whether it completes successfully or /// not. Essentially an asynchronous `finally` block. always(Future future, fn()) { - var completer = new Completer(); - future.then((_) => fn()); - future.handleException((_) { - fn(); - return false; - }); + future.catchError((_) {}).then((_) => fn()); } -/// Flattens nested collections into a single list containing only non-list -/// elements. -List flatten(Collection nested) { +/// Flattens nested lists inside an iterable into a single list containing only +/// non-list elements. +List flatten(Iterable nested) { var result = []; helper(list) { for (var element in list) { @@ -69,10 +65,11 @@ List flatten(Collection nested) { /// Asserts that [iter] contains only one element, and returns it. only(Iterable iter) { - var iterator = iter.iterator(); - assert(iterator.hasNext); - var obj = iterator.next(); - assert(!iterator.hasNext); + var iterator = iter.iterator; + var currentIsValid = iterator.moveNext(); + assert(currentIsValid); + var obj = iterator.current; + assert(!iterator.moveNext()); return obj; } @@ -108,7 +105,7 @@ bool endsWithPattern(String str, Pattern matcher) { /// Returns the hex-encoded sha1 hash of [source]. String sha1(String source) => - CryptoUtils.bytesToHex(new SHA1().update(source.charCodes).digest()); + CryptoUtils.bytesToHex(new SHA1().add(source.charCodes).close()); /// Returns a [Future] that completes in [milliseconds]. Future sleep(int milliseconds) { @@ -120,11 +117,11 @@ Future sleep(int milliseconds) { /// Configures [future] so that its result (success or exception) is passed on /// to [completer]. void chainToCompleter(Future future, Completer completer) { - future.handleException((e) { - completer.completeException(e, future.stackTrace); - return true; - }); - future.then(completer.complete); + future + .then(completer.complete) + .catchError((e) { + completer.completeError(e.error, e.stackTrace); + }); } // TODO(nweiz): unify the following functions with the utility functions in @@ -171,7 +168,7 @@ String mapToQuery(Map map) { value = (value == null || value.isEmpty) ? null : encodeUriComponent(value); pairs.add([key, value]); }); - return Strings.join(pairs.map((pair) { + return Strings.join(pairs.mappedBy((pair) { if (pair[1] == null) return pair[0]; return "${pair[0]}=${pair[1]}"; }), "&"); diff --git a/utils/pub/validator.dart b/utils/pub/validator.dart index 63a2386c072..70f5a9ffa24 100644 --- a/utils/pub/validator.dart +++ b/utils/pub/validator.dart @@ -55,10 +55,13 @@ abstract class Validator { // 3356, which causes a bug if all validators are (synchronously) using // Future.immediate and an error is thrown before a handler is set up. return sleep(0).chain((_) { - return Futures.wait(validators.map((validator) => validator.validate())); - }).transform((_) { - var errors = flatten(validators.map((validator) => validator.errors)); - var warnings = flatten(validators.map((validator) => validator.warnings)); + return Futures.wait( + validators.mappedBy((validator) => validator.validate())); + }).then((_) { + var errors = + flatten(validators.mappedBy((validator) => validator.errors)); + var warnings = + flatten(validators.mappedBy((validator) => validator.warnings)); if (!errors.isEmpty) { log.error("Missing requirements:"); diff --git a/utils/pub/validator/directory.dart b/utils/pub/validator/directory.dart index 07ad933ce56..80568bab2e8 100644 --- a/utils/pub/validator/directory.dart +++ b/utils/pub/validator/directory.dart @@ -17,8 +17,8 @@ class DirectoryValidator extends Validator { Future validate() { return listDir(entrypoint.root.dir).chain((dirs) { - return Futures.wait(dirs.map((dir) { - return dirExists(dir).transform((exists) { + return Futures.wait(dirs.mappedBy((dir) { + return dirExists(dir).then((exists) { if (!exists) return; dir = basename(dir); diff --git a/utils/pub/validator/lib.dart b/utils/pub/validator/lib.dart index b0dfbe5e51c..6afeb88fb0e 100644 --- a/utils/pub/validator/lib.dart +++ b/utils/pub/validator/lib.dart @@ -29,8 +29,8 @@ class LibValidator extends Validator { return new Future.immediate(null); } - return listDir(libDir).transform((files) { - files = files.map((file) => relativeTo(file, libDir)); + return listDir(libDir).then((files) { + files = files.mappedBy((file) => relativeTo(file, libDir)).toList(); if (files.isEmpty) { errors.add('You must have a non-empty "lib" directory.\n' "Without that, users cannot import any code from your package."); diff --git a/utils/pub/validator/license.dart b/utils/pub/validator/license.dart index fcc6a49c2f2..066ffbba188 100644 --- a/utils/pub/validator/license.dart +++ b/utils/pub/validator/license.dart @@ -15,10 +15,10 @@ class LicenseValidator extends Validator { : super(entrypoint); Future validate() { - return listDir(entrypoint.root.dir).transform((files) { + return listDir(entrypoint.root.dir).then((files) { var licenseLike = new RegExp( r"^([a-zA-Z0-9]+[-_])?(LICENSE|COPYING)(\..*)?$"); - if (files.map(basename).some(licenseLike.hasMatch)) return; + if (files.mappedBy(basename).any(licenseLike.hasMatch)) return; errors.add( "You must have a COPYING or LICENSE file in the root directory.\n" diff --git a/utils/pub/validator/name.dart b/utils/pub/validator/name.dart index 3d467c579bd..8d9e93dfe49 100644 --- a/utils/pub/validator/name.dart +++ b/utils/pub/validator/name.dart @@ -49,7 +49,7 @@ class NameValidator extends Validator { return dirExists(libDir).chain((libDirExists) { if (!libDirExists) return new Future.immediate([]); return listDir(libDir, recursive: true); - }).transform((files) { + }).then((files) { return files.map((file) => relativeTo(file, dirname(libDir))) .filter((file) { return !splitPath(file).contains("src") && diff --git a/utils/pub/version.dart b/utils/pub/version.dart index f60ad19cf6a..e7ca3d1299f 100644 --- a/utils/pub/version.dart +++ b/utils/pub/version.dart @@ -57,9 +57,9 @@ class Version implements Comparable, VersionConstraint { } try { - int major = parseInt(match[1]); - int minor = parseInt(match[2]); - int patch = parseInt(match[3]); + int major = int.parse(match[1]); + int minor = int.parse(match[2]); + int patch = int.parse(match[3]); String preRelease = match[5]; String build = match[8]; @@ -190,14 +190,14 @@ class Version implements Comparable, VersionConstraint { /// Splits a string of dot-delimited identifiers into their component parts. /// Identifiers that are numeric are converted to numbers. List _splitParts(String text) { - return text.split('.').map((part) { + return text.split('.').mappedBy((part) { try { - return parseInt(part); + return int.parse(part); } on FormatException catch (ex) { // Not a number. return part; } - }); + }).toList(); } } @@ -241,7 +241,7 @@ abstract class VersionConstraint { /// allow. If constraints is empty, then it returns a VersionConstraint that /// allows all versions. factory VersionConstraint.intersection( - Collection constraints) { + Iterable constraints) { var constraint = new VersionRange(); for (var other in constraints) { constraint = constraint.intersect(other); diff --git a/utils/pub/version_solver.dart b/utils/pub/version_solver.dart index a4b70f89a0c..f277169ffcf 100644 --- a/utils/pub/version_solver.dart +++ b/utils/pub/version_solver.dart @@ -35,7 +35,8 @@ /// the beginning again. library version_solver; -import 'dart:json'; +import 'dart:async'; +import 'dart:json' as json; import 'dart:math'; import 'lock_file.dart'; import 'log.dart' as log; @@ -116,7 +117,7 @@ class VersionSolver { // If we have an async operation to perform, chain the loop to resume // when it's done. Otherwise, just loop synchronously. if (future != null) { - return future.chain(processNextWorkItem); + return future.then(processNextWorkItem); } } } @@ -143,7 +144,7 @@ class VersionSolver { /// Returns the most recent version of [dependency] that satisfies all of its /// version constraints. Future getBestVersion(Dependency dependency) { - return dependency.getVersions().transform((versions) { + return dependency.getVersions().then((versions) { var best = null; for (var version in versions) { if (dependency.useLatestVersion || @@ -189,12 +190,12 @@ class VersionSolver { } } - return dependency.dependers.map(getDependency).some((subdependency) => + return dependency.dependers.mappedBy(getDependency).any((subdependency) => tryUnlockDepender(subdependency, seen)); } List buildResults() { - return _packages.values.filter((dep) => dep.isDependedOn).map((dep) { + return _packages.values.where((dep) => dep.isDependedOn).mappedBy((dep) { var description = dep.description; // If the lockfile contains a fully-resolved description for the package, @@ -208,7 +209,8 @@ class VersionSolver { } return new PackageId(dep.name, dep.source, dep.version, description); - }); + }) + .toList(); } } @@ -254,7 +256,7 @@ class ChangeVersion implements WorkItem { // them both and update any constraints that differ between the two. return Futures.wait([ getDependencyRefs(solver, oldVersion), - getDependencyRefs(solver, version)]).transform((list) { + getDependencyRefs(solver, version)]).then((list) { var oldDependencyRefs = list[0]; var newDependencyRefs = list[1]; @@ -289,7 +291,7 @@ class ChangeVersion implements WorkItem { } var id = new PackageId(package, source, version, description); - return solver._pubspecs.load(id).transform((pubspec) { + return solver._pubspecs.load(id).then((pubspec) { var dependencies = {}; for (var dependency in pubspec.dependencies) { dependencies[dependency.name] = dependency; @@ -364,7 +366,7 @@ abstract class ChangeConstraint implements WorkItem { // The constraint has changed, so see what the best version of the package // that meets the new constraint is. - return solver.getBestVersion(newDependency).transform((best) { + return solver.getBestVersion(newDependency).then((best) { if (best == null) { undo(solver); } else if (newDependency.version != best) { @@ -438,7 +440,7 @@ class UnlockPackage implements WorkItem { log.fine("Unlocking ${package.name}."); solver.lockFile.packages.remove(package.name); - return solver.getBestVersion(package).transform((best) { + return solver.getBestVersion(package).then((best) { if (best == null) return null; solver.enqueue(new ChangeVersion( package.name, package.source, package.description, best)); @@ -470,7 +472,7 @@ class PubspecCache { return new Future.immediate(_pubspecs[id]); } - return id.describe().transform((pubspec) { + return id.describe().then((pubspec) { // Cache it. _pubspecs[id] = pubspec; return pubspec; @@ -500,7 +502,7 @@ class Dependency { bool get isDependedOn => !_refs.isEmpty; /// The names of all the packages that depend on this dependency. - Collection get dependers => _refs.keys; + Iterable get dependers => _refs.keys; /// Gets the overall constraint that all packages are placing on this one. /// If no packages have a constraint on this one (which can happen when this @@ -508,7 +510,7 @@ class Dependency { VersionConstraint get constraint { if (_refs.isEmpty) return null; return new VersionConstraint.intersection( - _refs.values.map((ref) => ref.constraint)); + _refs.values.mappedBy((ref) => ref.constraint)); } /// The source of this dependency's package. @@ -535,7 +537,7 @@ class Dependency { for (var ref in refs) { if (ref is RootSource) return ref; } - return refs[0]; + return refs.first; } Dependency(this.name) @@ -576,7 +578,7 @@ class Dependency { String _requiredDepender() { if (_refs.isEmpty) return null; - var dependers = _refs.keys; + var dependers = _refs.keys.toList(); if (dependers.length == 1) { var depender = dependers[0]; if (_refs[depender].source is RootSource) return null; @@ -700,8 +702,8 @@ class DescriptionMismatchException implements Exception { // TODO(nweiz): Dump descriptions to YAML when that's supported. return "Incompatible dependencies on '$package':\n" "- '$depender1' depends on it with description " - "${JSON.stringify(description1)}\n" + "${json.stringify(description1)}\n" "- '$depender2' depends on it with description " - "${JSON.stringify(description2)}"; + "${json.stringify(description2)}"; } } diff --git a/utils/pub/yaml/composer.dart b/utils/pub/yaml/composer.dart index 79aa27411d0..e9c187969aa 100644 --- a/utils/pub/yaml/composer.dart +++ b/utils/pub/yaml/composer.dart @@ -115,7 +115,7 @@ class _Composer extends _Visitor { var match = new RegExp("^[-+]?[0-9]+\$").firstMatch(content); if (match != null) { return new _ScalarNode(_Tag.yaml("int"), - value: Math.parseInt(match.group(0))); + value: int.parse(match.group(0))); } match = new RegExp("^0o([0-7]+)\$").firstMatch(content); @@ -132,7 +132,7 @@ class _Composer extends _Visitor { match = new RegExp("^0x[0-9a-fA-F]+\$").firstMatch(content); if (match != null) { return new _ScalarNode(_Tag.yaml("int"), - value: Math.parseInt(match.group(0))); + value: int.parse(match.group(0))); } return null; @@ -148,20 +148,20 @@ class _Composer extends _Visitor { // floats by removing the trailing dot. var matchStr = match.group(0).replaceAll(new RegExp(r"\.$"), ""); return new _ScalarNode(_Tag.yaml("float"), - value: Math.parseDouble(matchStr)); + value: double.parse(matchStr)); } match = new RegExp("^([+-]?)\.(inf|Inf|INF)\$").firstMatch(content); if (match != null) { var infinityStr = match.group(1) == "-" ? "-Infinity" : "Infinity"; return new _ScalarNode(_Tag.yaml("float"), - value: Math.parseDouble(infinityStr)); + value: double.parse(infinityStr)); } match = new RegExp("^\.(nan|NaN|NAN)\$").firstMatch(content); if (match != null) { return new _ScalarNode(_Tag.yaml("float"), - value: Math.parseDouble("NaN")); + value: double.parse("NaN")); } return null; diff --git a/utils/pub/yaml/model.dart b/utils/pub/yaml/model.dart index 57bf202b543..8c111afe3d2 100644 --- a/utils/pub/yaml/model.dart +++ b/utils/pub/yaml/model.dart @@ -90,7 +90,8 @@ class _SequenceNode extends _Node { return true; } - String toString() => '$tag [${Strings.join(content.map((e) => '$e'), ', ')}]'; + String toString() => + '$tag [${Strings.join(content.mappedBy((e) => '$e'), ', ')}]'; int get hashCode => super.hashCode ^ _hashCode(content); @@ -149,7 +150,7 @@ class _ScalarNode extends _Node { // TODO(nweiz): This could be faster if we used a RegExp to check for // special characters and short-circuited if they didn't exist. - var escapedValue = value.charCodes.map((c) { + var escapedValue = value.charCodes.mappedBy((c) { switch (c) { case _Parser.TAB: return "\\t"; case _Parser.LF: return "\\n"; @@ -221,8 +222,9 @@ class _MappingNode extends _Node { } String toString() { - var strContent = Strings.join(content.keys. - map((k) => '${k}: ${content[k]}'), ', '); + var strContent = content.keys + .mappedBy((k) => '${k}: ${content[k]}') + .join(', '); return '$tag {$strContent}'; } diff --git a/utils/pub/yaml/parser.dart b/utils/pub/yaml/parser.dart index 8652ff45337..f2f255e7652 100644 --- a/utils/pub/yaml/parser.dart +++ b/utils/pub/yaml/parser.dart @@ -633,7 +633,7 @@ class _Parser { if (!captureAs('', () => consumeChar(char))) return false; var captured = captureAndTransform( () => nAtOnce(digits, (c, _) => isHexDigit(c)), - (hex) => new String.fromCharCodes([Math.parseInt("0x$hex")])); + (hex) => new String.fromCharCodes([int.parse("0x$hex")])); return expect(captured, "$digits hexidecimal digits"); } diff --git a/utils/pub/yaml/visitor.dart b/utils/pub/yaml/visitor.dart index 1d6282ae9c6..b5c14c9490d 100644 --- a/utils/pub/yaml/visitor.dart +++ b/utils/pub/yaml/visitor.dart @@ -13,7 +13,8 @@ class _Visitor { visitScalar(_ScalarNode scalar) => scalar; /// Visits each node in [seq] and returns a list of the results. - visitSequence(_SequenceNode seq) => seq.content.map((e) => e.visit(this)); + visitSequence(_SequenceNode seq) + => seq.content.mappedBy((e) => e.visit(this)).toList(); /// Visits each key and value in [map] and returns a map of the results. visitMapping(_MappingNode map) { diff --git a/utils/pub/yaml/yaml.dart b/utils/pub/yaml/yaml.dart index 11984c34d5f..6ce890ccf95 100644 --- a/utils/pub/yaml/yaml.dart +++ b/utils/pub/yaml/yaml.dart @@ -39,8 +39,9 @@ loadYaml(String yaml) { /// are YamlMaps. These have a few small behavioral differences from the default /// Map implementation; for details, see the YamlMap class. List loadYamlStream(String yaml) { - return new _Parser(yaml).l_yamlStream().map((doc) => - new _Constructor(new _Composer(doc).compose()).construct()); + return new _Parser(yaml).l_yamlStream().mappedBy((doc) => + new _Constructor(new _Composer(doc).compose()).construct()) + .toList(); } /// An error thrown by the YAML processor. diff --git a/utils/pub/yaml/yaml_map.dart b/utils/pub/yaml/yaml_map.dart index 285027ceaa2..65dd11994f0 100644 --- a/utils/pub/yaml/yaml_map.dart +++ b/utils/pub/yaml/yaml_map.dart @@ -29,8 +29,8 @@ class YamlMap implements Map { void clear() => _map.clear(); void forEach(void f(key, value)) => _map.forEach((k, v) => f(_unwrapKey(k), v)); - Collection get keys => _map.keys.map(_unwrapKey); - Collection get values => _map.values; + Iterable get keys => _map.keys.mappedBy(_unwrapKey); + Iterable get values => _map.values; int get length => _map.length; bool get isEmpty => _map.isEmpty; String toString() => _map.toString(); @@ -81,7 +81,7 @@ class _WrappedHashKey { int _hashCode(obj, [List parents]) { if (parents == null) { parents = []; - } else if (parents.some((p) => identical(p, obj))) { + } else if (parents.any((p) => identical(p, obj))) { return -1; } @@ -94,7 +94,7 @@ int _hashCode(obj, [List parents]) { return _hashCode(obj.keys, parents) ^ _hashCode(obj.values, parents); } - if (obj is List) { + if (obj is Iterable) { // This is probably a really bad hash function, but presumably we'll get // this in the standard library before it actually matters. int hash = 0; diff --git a/utils/template/parser.dart b/utils/template/parser.dart index 120e2692e47..e0f426c3bef 100644 --- a/utils/template/parser.dart +++ b/utils/template/parser.dart @@ -454,7 +454,7 @@ class Parser { } if (scopeType > 0) { var elem = new TemplateElement.attributes(tagToken.kind, - attrs.values, varName, _makeSpan(start)); + attrs.values.toList(), varName, _makeSpan(start)); stack.top().add(elem); if (scopeType == 1) { diff --git a/utils/template/utils.dart b/utils/template/utils.dart index dcd19424bb9..c9b80422877 100644 --- a/utils/template/utils.dart +++ b/utils/template/utils.dart @@ -7,7 +7,7 @@ // TODO(jmesserly): we might want a version of this that return an iterable, // however JS, Python and Ruby versions are all eager. -List map(Iterable source, mapper(source)) { +List mappedBy(Iterable source, mapper(source)) { List result = new List(); if (source is List) { List list = source; // TODO: shouldn't need this @@ -24,26 +24,29 @@ List map(Iterable source, mapper(source)) { } reduce(Iterable source, callback, [initialValue]) { - final i = source.iterator(); + final i = source.iterator; var current = initialValue; - if (current == null && i.hasNext) { - current = i.next(); + if (current == null && i.moveNext()) { + current = i.current; } - while (i.hasNext) { - current = callback(current, i.next()); + while (i.moveNext()) { + current = callback(current, i.current); } return current; } List zip(Iterable left, Iterable right, mapper(left, right)) { List result = new List(); - var x = left.iterator(); - var y = right.iterator(); - while (x.hasNext && y.hasNext) { - result.add(mapper(x.next(), y.next())); + var x = left.iterator; + var y = right.iterator; + while (x.moveNext()) { + if (!y.moveNext()) { + throw new ArgumentError(); + } + result.add(mapper(x.current, y.current)); } - if (x.hasNext || y.hasNext) { + if (y.moveNext()) { throw new ArgumentError(); } return result; diff --git a/utils/testrunner/options.dart b/utils/testrunner/options.dart index c05773de79c..5d21bd43524 100644 --- a/utils/testrunner/options.dart +++ b/utils/testrunner/options.dart @@ -200,7 +200,7 @@ ArgResults loadConfiguration(optionsParser) { var options = new List(); // We first load options from a test.config file in the working directory. options.addAll(getFileContents('test.config', false). - filter((e) => e.trim().length > 0 && e[0] != '#')); + where((e) => e.trim().length > 0 && e[0] != '#')); // Next we look to see if the command line included a -testconfig argument, // and if so, load options from that file too; where these are not // multi-valued they will take precedence over the ones in test.config. @@ -213,11 +213,11 @@ ArgResults loadConfiguration(optionsParser) { throw new Exception('Missing argument to $cfgarg'); } options.addAll(getFileContents(commandLineArgs[++i], true). - filter((e) => e.trim().length > 0 && e[0] != '#')); + where((e) => e.trim().length > 0 && e[0] != '#')); } else if (commandLineArgs[i].startsWith('$cfgarg=')) { options.addAll( getFileContents(commandLineArgs[i].substring(cfgarg.length), true). - filter((e) => e.trim().length > 0 && e[0] != '#')); + where((e) => e.trim().length > 0 && e[0] != '#')); } else { throw new Exception('Missing argument to $cfgarg'); } diff --git a/utils/testrunner/run_pipeline.dart b/utils/testrunner/run_pipeline.dart index 3b21cad92e8..ba0f75d3cc3 100644 --- a/utils/testrunner/run_pipeline.dart +++ b/utils/testrunner/run_pipeline.dart @@ -6,7 +6,6 @@ library pipeline; import 'dart:isolate'; import 'dart:io'; -import 'dart:math'; part 'pipeline_utils.dart'; /** @@ -84,7 +83,7 @@ startHTTPServerStage() { var r = new Random(); tryStartHTTPServer(r, MAX_SERVER_TRIES); } else { - serverPort = parseInt(config["port"]); + serverPort = int.parse(config["port"]); // Start the HTTP server. serverId = startProcess(config["dart"], [ serverPath, '--port=$serverPort', '--root=$serverRoot']); diff --git a/utils/tests/archive/reader_test.dart b/utils/tests/archive/reader_test.dart index 77fd88f2bb4..55a0a14ab5a 100644 --- a/utils/tests/archive/reader_test.dart +++ b/utils/tests/archive/reader_test.dart @@ -19,7 +19,7 @@ main() { reader.filter.gzip = true; var future = reader.openFilename("$dataPath/test-archive.tar.gz") - .transform((input) { + .then((input) { var log = []; input.onEntry = (entry) => guardAsync(() { log.add("Entry: ${entry.pathname}"); @@ -56,8 +56,10 @@ main() { var future = reader.openFilename("$dataPath/test-archive.tar.gz") .chain((input) => input.readAll()) - .transform((entries) { - entries = entries.map((entry) => [entry.pathname, entry.contents.trim()]); + .then((entries) { + entries = entries + .mappedBy((entry) => [entry.pathname, entry.contents.trim()]) + .toList(); expect(entries[0], orderedEquals(["filename1", "contents 1"])); expect(entries[1], orderedEquals(["filename2", "contents 2"])); expect(entries[2], orderedEquals(["filename3", "contents 3"])); @@ -75,7 +77,7 @@ main() { var future = new File("$dataPath/test-archive.tar.gz").readAsBytes() .chain((bytes) => reader.openData(bytes)) - .transform((input) { + .then((input) { var log = []; input.onEntry = (entry) => guardAsync(() { log.add("Entry: ${entry.pathname}"); @@ -113,7 +115,7 @@ main() { reader.filter.gzip = true; var future = reader.openFilename("$dataPath/test-archive.tar.gz") - .transform((input) { + .then((input) { var log = []; input.onEntry = (entry) => guardAsync(() { log.add("Entry: ${entry.pathname}"); @@ -150,7 +152,7 @@ main() { reader.filter.gzip = true; var future = reader.openFilename("$dataPath/test-archive.tar.gz") - .transform((input) { + .then((input) { var count = 0; var log = []; diff --git a/utils/tests/pub/curl_client_test.dart b/utils/tests/pub/curl_client_test.dart index c040c2db66e..c2f6fb3f185 100644 --- a/utils/tests/pub/curl_client_test.dart +++ b/utils/tests/pub/curl_client_test.dart @@ -215,7 +215,7 @@ void main() { tearDown(stopServer); test('head', () { - expect(new CurlClient().head(serverUrl).transform((response) { + expect(new CurlClient().head(serverUrl).then((response) { expect(response.statusCode, equals(200)); expect(response.body, equals('')); }), completes); @@ -225,7 +225,7 @@ void main() { expect(new CurlClient().get(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'GET', @@ -245,7 +245,7 @@ void main() { }, fields: { 'some-field': 'value', 'other-field': 'other value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'POST', @@ -268,7 +268,7 @@ void main() { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value', 'Content-Type': 'text/plain' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'POST', @@ -289,7 +289,7 @@ void main() { }, fields: { 'some-field': 'value', 'other-field': 'other value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'PUT', @@ -312,7 +312,7 @@ void main() { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value', 'Content-Type': 'text/plain' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'PUT', @@ -330,7 +330,7 @@ void main() { expect(new CurlClient().delete(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'DELETE', @@ -366,7 +366,7 @@ void main() { var future = new CurlClient().readBytes(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((bytes) => new String.fromCharCodes(bytes)); + }).then((bytes) => new String.fromCharCodes(bytes)); expect(future, completion(parse(equals({ 'method': 'GET', @@ -389,11 +389,11 @@ void main() { request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json; charset=utf-8'; - var future = client.send(request).chain((response) { + var future = client.send(request).then((response) { expect(response.statusCode, equals(200)); return consumeInputStream(response.stream); - }).transform((bytes) => new String.fromCharCodes(bytes)); - future.onComplete((_) => client.close()); + }).then((bytes) => new String.fromCharCodes(bytes)); + future.catchError((_) {}).then((_) => client.close()); expect(future, completion(parse(equals({ 'method': 'POST', @@ -411,7 +411,7 @@ void main() { test('with one redirect', () { var url = serverUrl.resolve('/redirect'); - expect(new CurlClient().get(url).transform((response) { + expect(new CurlClient().get(url).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'GET', @@ -433,7 +433,7 @@ void main() { test('with one redirect via HEAD', () { var url = serverUrl.resolve('/redirect'); - expect(new CurlClient().head(url).transform((response) { + expect(new CurlClient().head(url).then((response) { expect(response.statusCode, equals(200)); }), completes); }); @@ -451,8 +451,8 @@ void main() { test('without following redirects', () { var request = new http.Request('GET', serverUrl.resolve('/redirect')); request.followRedirects = false; - expect(new CurlClient().send(request).chain(http.Response.fromStream) - .transform((response) { + expect(new CurlClient().send(request).then(http.Response.fromStream) + .then((response) { expect(response.statusCode, equals(302)); expect(response.isRedirect, true); }), completes); diff --git a/utils/tests/pub/oauth2_test.dart b/utils/tests/pub/oauth2_test.dart index f3d38e04a08..d8f3b34a048 100644 --- a/utils/tests/pub/oauth2_test.dart +++ b/utils/tests/pub/oauth2_test.dart @@ -68,7 +68,7 @@ main() { confirmPublish(pub); server.handle('POST', '/token', (request, response) { - return consumeInputStream(request.inputStream).transform((bytes) { + return consumeInputStream(request.inputStream).then((bytes) { var body = new String.fromCharCodes(bytes); expect(body, matches( new RegExp(r'(^|&)refresh_token=refresh\+token(&|$)'))); @@ -199,7 +199,7 @@ void authorizePub(ScheduledProcess pub, ScheduledServer server, redirectUrl = addQueryParameters(redirectUrl, {'code': 'access code'}); return (new http.Request('GET', redirectUrl)..followRedirects = false) .send(); - }).transform((response) { + }).then((response) { expect(response.headers['location'], equals(['http://pub.dartlang.org/authorized'])); }), anything); @@ -209,7 +209,7 @@ void authorizePub(ScheduledProcess pub, ScheduledServer server, void handleAccessTokenRequest(ScheduledServer server, String accessToken) { server.handle('POST', '/token', (request, response) { - return consumeInputStream(request.inputStream).transform((bytes) { + return consumeInputStream(request.inputStream).then((bytes) { var body = new String.fromCharCodes(bytes); expect(body, matches(new RegExp(r'(^|&)code=access\+code(&|$)'))); diff --git a/utils/tests/pub/pub_lish_test.dart b/utils/tests/pub/pub_lish_test.dart index 695557848e9..5319c466785 100644 --- a/utils/tests/pub/pub_lish_test.dart +++ b/utils/tests/pub/pub_lish_test.dart @@ -13,7 +13,7 @@ import '../../pub/io.dart'; void handleUploadForm(ScheduledServer server, [Map body]) { server.handle('GET', '/packages/versions/new.json', (request, response) { - return server.url.transform((url) { + return server.url.then((url) { expect(request.headers.value('authorization'), equals('Bearer access token')); @@ -38,7 +38,7 @@ void handleUpload(ScheduledServer server) { server.handle('POST', '/upload', (request, response) { // TODO(nweiz): Once a multipart/form-data parser in Dart exists, validate // that the request body is correctly formatted. See issue 6952. - return server.url.transform((url) { + return server.url.then((url) { response.statusCode = 302; response.headers.set('location', url.resolve('/create').toString()); response.outputStream.close(); diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart index 3da8fce9794..a6042fb8737 100644 --- a/utils/tests/pub/test_pub.dart +++ b/utils/tests/pub/test_pub.dart @@ -8,9 +8,9 @@ /// tests like that. library test_pub; +import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:math'; import 'dart:uri'; @@ -80,7 +80,7 @@ void serve([List contents]) { var baseDir = dir("serve-dir", contents); _schedule((_) { - return _closeServer().transform((_) { + return _closeServer().then((_) { _server = new HttpServer(); _server.defaultRequestHandler = (request, response) { var path = request.uri.replaceFirst("/", "").split("/"); @@ -101,9 +101,7 @@ void serve([List contents]) { response.contentLength = data.length; response.outputStream.write(data); response.outputStream.close(); - }); - - future.handleException((e) { + }).catchError((e) { print("Exception while handling ${request.uri}: $e"); response.statusCode = 500; response.reasonPhrase = e.message; @@ -161,7 +159,7 @@ void servePackages(List pubspecs) { } _schedule((_) { - return _awaitObject(pubspecs).transform((resolvedPubspecs) { + return _awaitObject(pubspecs).then((resolvedPubspecs) { for (var spec in resolvedPubspecs) { var name = spec['name']; var version = spec['version']; @@ -172,12 +170,12 @@ void servePackages(List pubspecs) { _servedPackageDir.contents.clear(); for (var name in _servedPackages.keys) { - var versions = _servedPackages[name].keys; + var versions = _servedPackages[name].keys.toList()); _servedPackageDir.contents.addAll([ file('$name.json', - JSON.stringify({'versions': versions})), + json.stringify({'versions': versions})), dir(name, [ - dir('versions', flatten(versions.map((version) { + dir('versions', flatten(versions.mappedBy((version) { return [ file('$version.yaml', _servedPackages[name][version]), tar('$version.tar.gz', [ @@ -194,7 +192,7 @@ void servePackages(List pubspecs) { } /// Converts [value] into a YAML string. -String yaml(value) => JSON.stringify(value); +String yaml(value) => json.stringify(value); /// Describes a package that passes all validation. Descriptor get normalPackage => dir(appPath, [ @@ -211,7 +209,7 @@ Descriptor get normalPackage => dir(appPath, [ /// [contents] may contain [Future]s that resolve to serializable objects, /// which may in turn contain [Future]s recursively. Descriptor pubspec(Map contents) { - return async(_awaitObject(contents).transform((resolvedContents) => + return async(_awaitObject(contents).then((resolvedContents) => file("pubspec.yaml", yaml(resolvedContents)))); } @@ -261,7 +259,7 @@ Map package(String name, String version, [List dependencies]) { /// Describes a map representing a dependency on a package in the package /// repository. Map dependency(String name, [String versionConstraint]) { - var url = port.transform((p) => "http://localhost:$p"); + var url = port.then((p) => "http://localhost:$p"); var dependency = {"hosted": {"name": name, "url": url}}; if (versionConstraint != null) dependency["version"] = versionConstraint; return dependency; @@ -331,7 +329,7 @@ DirectoryDescriptor cacheDir(Map packages) { }); return dir(cachePath, [ dir('hosted', [ - async(port.transform((p) => dir('localhost%58$p', contents))) + async(port.then((p) => dir('localhost%58$p', contents))) ]) ]); } @@ -344,7 +342,7 @@ Descriptor credentialsFile( String accessToken, {String refreshToken, Date expiration}) { - return async(server.url.transform((url) { + return async(server.url.then((url) { return dir(cachePath, [ file('credentials.json', new oauth2.Credentials( accessToken, @@ -364,10 +362,10 @@ DirectoryDescriptor appDir(List dependencies) => /// Converts a list of dependencies as passed to [package] into a hash as used /// in a pubspec. Future _dependencyListToMap(List dependencies) { - return _awaitObject(dependencies).transform((resolvedDependencies) { + return _awaitObject(dependencies).then((resolvedDependencies) { var result = {}; for (var dependency in resolvedDependencies) { - var keys = dependency.keys.filter((key) => key != "version"); + var keys = dependency.keys.where((key) => key != "version"); var sourceName = only(keys); var source; switch (sourceName) { @@ -453,7 +451,7 @@ void run() { var asyncDone = expectAsync0(() {}); Future cleanup() { - return _runScheduled(createdSandboxDir, _scheduledCleanup).chain((_) { + return _runScheduled(createdSandboxDir, _scheduledCleanup).then((_) { _scheduled = null; _scheduledCleanup = null; _scheduledOnException = null; @@ -462,29 +460,25 @@ void run() { }); } - final future = _setUpSandbox().chain((sandboxDir) { + final future = _setUpSandbox().then((sandboxDir) { createdSandboxDir = sandboxDir; return _runScheduled(sandboxDir, _scheduled); }); - future.handleException((error) { + future.catchError((error) { // If an error occurs during testing, delete the sandbox, throw the error so // that the test framework sees it, then finally call asyncDone so that the // test framework knows we're done doing asynchronous stuff. var subFuture = _runScheduled(createdSandboxDir, _scheduledOnException) - .chain((_) => cleanup()); - subFuture.handleException((e) { - print("Exception while cleaning up: $e"); - print(subFuture.stackTrace); - registerException(error, subFuture.stackTrace); + .then((_) => cleanup()); + subFuture.catchError((e) { + print("Exception while cleaning up: ${e.error}"); + print(e.stackTrace); + registerException(e.error, e.stackTrace); return true; }); - subFuture.then((_) => registerException(error, future.stackTrace)); - return true; - }); - timeout(future, _TIMEOUT, 'waiting for a test to complete') - .chain((_) => cleanup()) + .then((_) => cleanup()) .then((_) => asyncDone()); } @@ -503,7 +497,7 @@ void schedulePub({List args, Pattern output, Pattern error, Future tokenEndpoint, int exitCode: 0}) { _schedule((sandboxDir) { return _doPub(runProcess, sandboxDir, args, tokenEndpoint) - .transform((result) { + .then((result) { var failures = []; _validateOutput(failures, 'stdout', output, result.stdout); @@ -518,7 +512,7 @@ void schedulePub({List args, Pattern output, Pattern error, if (error == null) { // If we aren't validating the error, still show it on failure. failures.add('Pub stderr:'); - failures.addAll(result.stderr.map((line) => '| $line')); + failures.addAll(result.stderr.mappedBy((line) => '| $line')); } throw new ExpectException(Strings.join(failures, '\n')); @@ -629,7 +623,7 @@ Future _doPub(Function fn, sandboxDir, List args, Future tokenEndpoint) { /// about the pub git tests). void ensureGit() { _schedule((_) { - return isGitInstalled.transform((installed) { + return isGitInstalled.then((installed) { if (!installed && !Platform.environment.containsKey('BUILDBOT_BUILDERNAME')) { _abortScheduled = true; @@ -655,18 +649,18 @@ Future _setUpSandbox() => createTempDir(); Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) { if (scheduled == null) return new Future.immediate(null); - var iterator = scheduled.iterator(); + var iterator = scheduled.iterator; Future runNextEvent(_) { - if (_abortScheduled || !iterator.hasNext) { + if (_abortScheduled || !iterator.moveNext()) { _abortScheduled = false; scheduled.clear(); return new Future.immediate(null); } - var future = iterator.next()(parentDir); + var future = iterator.current(parentDir); if (future != null) { - return future.chain(runNextEvent); + return future.then(runNextEvent); } else { return runNextEvent(null); } @@ -699,7 +693,7 @@ void _validateOutputRegex(List failures, String pipe, failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); } else { failures.add('Expected $pipe to match "${expected.pattern}" but got:'); - failures.addAll(actual.map((line) => '| $line')); + failures.addAll(actual.mappedBy((line) => '| $line')); } } @@ -744,7 +738,7 @@ void _validateOutputString(List failures, String pipe, // If any lines mismatched, show the expected and actual. if (failed) { failures.add('Expected $pipe:'); - failures.addAll(expected.map((line) => '| $line')); + failures.addAll(expected.mappedBy((line) => '| $line')); failures.add('Got:'); failures.addAll(results); } @@ -802,7 +796,7 @@ abstract class Descriptor { // Special-case strings to support multi-level names like "myapp/packages". if (name is String) { var path = join(dir, name); - return exists(path).chain((exists) { + return exists(path).then((exists) { if (!exists) Expect.fail('File $name in $dir not found.'); return validate(path); }); @@ -816,9 +810,9 @@ abstract class Descriptor { stackTrace = localStackTrace; } - return listDir(dir).chain((files) { - var matches = files.filter((file) => endsWithPattern(file, name)); - if (matches.length == 0) { + return listDir(dir).then((files) { + var matches = files.where((file) => endsWithPattern(file, name)).toList(); + if (matches.isEmpty) { Expect.fail('No files in $dir match pattern $name.'); } if (matches.length == 1) return validate(matches[0]); @@ -845,16 +839,15 @@ abstract class Descriptor { for (var match in matches) { var future = validate(match); - future.handleException((e) { + future.catchError((e) { failures.add(e); checkComplete(); - return true; }); future.then((_) { successes++; checkComplete(); - }); + }).catchError(() {}); } return completer.future; }); @@ -885,7 +878,7 @@ class FileDescriptor extends Descriptor { /// Validates that this file correctly matches the actual file at [path]. Future validate(String path) { return _validateOneMatch(path, (file) { - return readTextFile(file).transform((text) { + return readTextFile(file).then((text) { if (text == contents) return null; Expect.fail('File $file should contain:\n\n$contents\n\n' @@ -923,13 +916,14 @@ class DirectoryDescriptor extends Descriptor { /// the creation is done. Future create(parentDir) { // Create the directory. - return ensureDir(join(parentDir, _stringName)).chain((dir) { + return ensureDir(join(parentDir, _stringName)).then((dir) { if (contents == null) return new Future.immediate(dir); // Recursively create all of its children. - final childFutures = contents.map((child) => child.create(dir)); + final childFutures = + contents.mappedBy((child) => child.create(dir)).toList(); // Only complete once all of the children have been created too. - return Futures.wait(childFutures).transform((_) => dir); + return Futures.wait(childFutures).then((_) => dir); }); } @@ -946,10 +940,11 @@ class DirectoryDescriptor extends Descriptor { Future validate(String path) { return _validateOneMatch(path, (dir) { // Validate each of the items in this directory. - final entryFutures = contents.map((entry) => entry.validate(dir)); + final entryFutures = + contents.mappedBy((entry) => entry.validate(dir)).toList(); // If they are all valid, the directory is valid. - return Futures.wait(entryFutures).transform((entries) => null); + return Futures.wait(entryFutures).then((entries) => null); }); } @@ -978,11 +973,11 @@ class FutureDescriptor extends Descriptor { FutureDescriptor(this._future) : super(''); - Future create(dir) => _future.chain((desc) => desc.create(dir)); + Future create(dir) => _future.then((desc) => desc.create(dir)); - Future validate(dir) => _future.chain((desc) => desc.validate(dir)); + Future validate(dir) => _future.then((desc) => desc.validate(dir)); - Future delete(dir) => _future.chain((desc) => desc.delete(dir)); + Future delete(dir) => _future.then((desc) => desc.delete(dir)); InputStream load(List path) { var resultStream = new ListInputStream(); @@ -1020,9 +1015,9 @@ class GitRepoDescriptor extends DirectoryDescriptor { /// referred to by [ref] at the current point in the scheduled test run. Future revParse(String ref) { return _scheduleValue((parentDir) { - return super.create(parentDir).chain((rootDir) { + return super.create(parentDir).then((rootDir) { return _runGit(['rev-parse', ref], rootDir); - }).transform((output) => output[0]); + }).then((output) => output[0]); }); } @@ -1040,10 +1035,10 @@ class GitRepoDescriptor extends DirectoryDescriptor { Future runGitStep(_) { if (commands.isEmpty) return new Future.immediate(workingDir); var command = commands.removeAt(0); - return _runGit(command, workingDir).chain(runGitStep); + return _runGit(command, workingDir).then(runGitStep); } - return super.create(parentDir).chain((rootDir) { + return super.create(parentDir).then((rootDir) { workingDir = rootDir; return runGitStep(null); }); @@ -1060,7 +1055,7 @@ class GitRepoDescriptor extends DirectoryDescriptor { }; return runGit(args, workingDir: workingDir.path, - environment: environment).transform((result) { + environment: environment).then((result) { if (!result.success) { throw "Error running: git ${Strings.join(args, ' ')}\n" "${Strings.join(result.stderr, '\n')}"; @@ -1083,15 +1078,15 @@ class TarFileDescriptor extends Descriptor { Future create(parentDir) { // TODO(rnystrom): Use withTempDir(). var tempDir; - return createTempDir().chain((_tempDir) { + return createTempDir().then((_tempDir) { tempDir = _tempDir; - return Futures.wait(contents.map((child) => child.create(tempDir))); - }).chain((createdContents) { + return Futures.wait(contents.mappedBy((child) => child.create(tempDir))); + }).then((createdContents) { return consumeInputStream(createTarGz(createdContents, baseDir: tempDir)); - }).chain((bytes) { + }).then((bytes) { return new File(join(parentDir, _stringName)).writeAsBytes(bytes); - }).chain((file) { - return deleteDir(tempDir).transform((_) => file); + }).then((file) { + return deleteDir(tempDir).then((_) => file); }); } @@ -1116,7 +1111,7 @@ class TarFileDescriptor extends Descriptor { var tempDir; // TODO(rnystrom): Use withTempDir() here. // TODO(nweiz): propagate any errors to the return value. See issue 3657. - createTempDir().chain((_tempDir) { + createTempDir().then((_tempDir) { tempDir = _tempDir; return create(tempDir); }).then((tar) { @@ -1137,7 +1132,7 @@ class NothingDescriptor extends Descriptor { Future delete(dir) => new Future.immediate(null); Future validate(String dir) { - return exists(join(dir, name)).transform((exists) { + return exists(join(dir, name)).then((exists) { if (exists) Expect.fail('File $name in $dir should not exist.'); }); } @@ -1167,7 +1162,7 @@ Future, List>> schedulePackageValidation( return Entrypoint.load(join(sandboxDir, appPath), cache) .chain((entrypoint) { var validator = fn(entrypoint); - return validator.validate().transform((_) { + return validator.validate().then((_) { return new Pair(validator.errors, validator.warnings); }); }); @@ -1240,8 +1235,8 @@ class ScheduledProcess { /// Wraps a [Process] [Future] in a scheduled process. ScheduledProcess(this.name, Future process) : _process = process, - _stdout = process.transform((p) => new StringInputStream(p.stdout)), - _stderr = process.transform((p) => new StringInputStream(p.stderr)) { + _stdout = process.then((p) => new StringInputStream(p.stdout)), + _stderr = process.then((p) => new StringInputStream(p.stderr)) { _schedule((_) { if (!_endScheduled) { @@ -1249,7 +1244,7 @@ class ScheduledProcess { "or kill() called before the test is run."); } - return _process.transform((p) { + return _process.then((p) { p.onExit = (c) { if (_endExpected) { _exitCodeCompleter.complete(c); @@ -1343,7 +1338,7 @@ class ScheduledProcess { /// Writes [line] to the process as stdin. void writeLine(String line) { - _schedule((_) => _process.transform((p) => p.stdin.writeString('$line\n'))); + _schedule((_) => _process.then((p) => p.stdin.writeString('$line\n'))); } /// Kills the process, and waits until it's dead. @@ -1366,7 +1361,7 @@ class ScheduledProcess { _schedule((_) { _endExpected = true; return timeout(_exitCode, _SCHEDULE_TIMEOUT, - "waiting for process $name to exit").transform((exitCode) { + "waiting for process $name to exit").then((exitCode) { if (expectedExitCode != null) { expect(exitCode, equals(expectedExitCode)); } @@ -1378,7 +1373,7 @@ class ScheduledProcess { /// Prints nothing if the straems are empty. Future _printStreams() { Future printStream(String streamName, StringInputStream stream) { - return consumeStringInputStream(stream).transform((output) { + return consumeStringInputStream(stream).then((output) { if (output.isEmpty) return; print('\nProcess $name $streamName:'); @@ -1424,11 +1419,11 @@ class ScheduledServer { } /// The port on which the server is listening. - Future get port => _server.transform((s) => s.port); + Future get port => _server.then((s) => s.port); /// The base URL of the server, including its port. Future get url => - port.transform((p) => new Uri.fromString("http://localhost:$p")); + port.then((p) => new Uri.fromString("http://localhost:$p")); /// Assert that the next request has the given [method] and [path], and pass /// it to [handler] to handle. If [handler] returns a [Future], wait until @@ -1466,7 +1461,7 @@ class ScheduledServer { fail('Unexpected ${request.method} request to ${request.path}.'); } return _handlers.removeFirst(); - }).transform((handler) { + }).then((handler) { handler(request, response); }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " "${request.path}"); @@ -1479,16 +1474,18 @@ class ScheduledServer { /// Completes with the fully resolved structure. Future _awaitObject(object) { // Unroll nested futures. - if (object is Future) return object.chain(_awaitObject); - if (object is Collection) return Futures.wait(object.map(_awaitObject)); + if (object is Future) return object.then(_awaitObject); + if (object is Collection) { + return Futures.wait(object.mappedBy(_awaitObject).toList()); + } if (object is! Map) return new Future.immediate(object); var pairs = >[]; object.forEach((key, value) { pairs.add(_awaitObject(value) - .transform((resolved) => new Pair(key, resolved))); + .then((resolved) => new Pair(key, resolved))); }); - return Futures.wait(pairs).transform((resolvedPairs) { + return Futures.wait(pairs).then((resolvedPairs) { var map = {}; for (var pair in resolvedPairs) { map[pair.first] = pair.last; @@ -1537,7 +1534,7 @@ void _scheduleOnException(_ScheduledEvent event) { void expectLater(Future actual, matcher, {String reason, FailureHandler failureHandler, bool verbose: false}) { _schedule((_) { - return actual.transform((value) { + return actual.then((value) { expect(value, matcher, reason: reason, failureHandler: failureHandler, verbose: false); }); diff --git a/utils/tests/pub/version_solver_test.dart b/utils/tests/pub/version_solver_test.dart index eb49d3d8236..b5b30eda77d 100644 --- a/utils/tests/pub/version_solver_test.dart +++ b/utils/tests/pub/version_solver_test.dart @@ -4,8 +4,8 @@ library pub_update_test; +import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; import '../../pub/lock_file.dart'; import '../../pub/package.dart'; @@ -452,10 +452,9 @@ testResolve(description, packages, {lockfile, result, Matcher error}) { // If we aren't expecting an error, print some debugging info if we get one. if (error == null) { - future.handleException((ex) { + future.catchError((ex) { print(ex); print(future.stackTrace); - return true; }); } }); @@ -478,7 +477,7 @@ class MockSource extends Source { : _packages = >{}; Future> getVersions(String name, String description) { - return fakeAsync(() => _packages[description].keys); + return fakeAsync(() => _packages[description].keys.toList()); } Future describe(PackageId id) { diff --git a/utils/tests/pub/yaml_test.dart b/utils/tests/pub/yaml_test.dart index 85cbdf81b71..889923e54d2 100644 --- a/utils/tests/pub/yaml_test.dart +++ b/utils/tests/pub/yaml_test.dart @@ -4,8 +4,6 @@ library yaml_test; -import 'dart:math'; - import '../../../pkg/unittest/lib/unittest.dart'; import '../../pub/yaml/yaml.dart'; import '../../pub/yaml/deep_equals.dart'; @@ -32,8 +30,8 @@ expectYamlStreamLoads(List expected, String source) { } main() { - var infinity = parseDouble("Infinity"); - var nan = parseDouble("NaN"); + var infinity = double.parse("Infinity"); + var nan = double.parse("NaN"); group('YamlMap', () { group('accepts as a key', () { diff --git a/utils/tests/string_encoding/benchmark_runner.dart b/utils/tests/string_encoding/benchmark_runner.dart index 225a1dc0445..7af2ead095d 100644 --- a/utils/tests/string_encoding/benchmark_runner.dart +++ b/utils/tests/string_encoding/benchmark_runner.dart @@ -104,8 +104,7 @@ class TestReport { } int resultsMeanNanos() => - (BlockSample._totalTime(results) / - BlockSample._totalCount(results)).toInt(); + BlockSample._totalTime(results) ~/ BlockSample._totalCount(results); int resultsWorstNanos() { BlockSample worst = worstBlock(results); @@ -199,7 +198,7 @@ class Runner { static bool runTest(String testId) { Options opts = new Options(); return opts.arguments.length == 0 || - opts.arguments.some(_(String id) => id == testId); + opts.arguments.any((String id) => id == testId); } } diff --git a/utils/tests/string_encoding/dunit.dart b/utils/tests/string_encoding/dunit.dart index 716acb49044..3c092b376e6 100644 --- a/utils/tests/string_encoding/dunit.dart +++ b/utils/tests/string_encoding/dunit.dart @@ -37,15 +37,15 @@ class TestSuite { print("OK -- ALL TESTS PASS (${results.length} run)"); } else { for(TestResult r in - results.filter(bool _(TestResult r) => !(r is PassedTest))) { + results.where(bool _(TestResult r) => !(r is PassedTest))) { print(r); } int passedTests = - results.filter(bool _(TestResult r) => r is PassedTest).length; + results.where(bool _(TestResult r) => r is PassedTest).length; int failures = - results.filter(bool _(TestResult r) => r is FailedTest).length; + results.where(bool _(TestResult r) => r is FailedTest).length; int errors = - results.filter(bool _(TestResult r) => r is TestError).length; + results.where(bool _(TestResult r) => r is TestError).length; print("FAIL -- TESTS RUN: ${results.length}"); print(" PASSED: ${passedTests}"); print(" FAILED: ${failures}"); diff --git a/utils/tests/string_encoding/utf16_test.dart b/utils/tests/string_encoding/utf16_test.dart index a55f760f0be..004dcf0a76c 100755 --- a/utils/tests/string_encoding/utf16_test.dart +++ b/utils/tests/string_encoding/utf16_test.dart @@ -113,13 +113,12 @@ class Utf16Tests extends TestClass { void testIterableMethods() { // empty input - Expect.isFalse(decodeUtf16AsIterable([]).iterator().hasNext); + Expect.isFalse(decodeUtf16AsIterable([]).iterator.moveNext()); IterableUtf16Decoder koreanDecoder = decodeUtf16AsIterable(testKoreanCharSubsetUtf16beBom); // get the first character - Expect.equals(testKoreanCharSubset.charCodes[0], - koreanDecoder.iterator().next()); + Expect.equals(testKoreanCharSubset.charCodes[0], koreanDecoder.first); // get the whole translation using the Iterable interface Expect.stringEquals(testKoreanCharSubset, new String.fromCharCodes(new List.from(koreanDecoder))); diff --git a/utils/tests/string_encoding/utf32_test.dart b/utils/tests/string_encoding/utf32_test.dart index 7b6582455df..eb727bc74e8 100755 --- a/utils/tests/string_encoding/utf32_test.dart +++ b/utils/tests/string_encoding/utf32_test.dart @@ -165,13 +165,13 @@ class Utf32Tests extends TestClass { void testIterableMethods() { // empty input - Expect.isFalse(decodeUtf32AsIterable([]).iterator().hasNext); + Expect.isFalse(decodeUtf32AsIterable([]).iterator.moveNext()); IterableUtf32Decoder koreanDecoder = decodeUtf32AsIterable(testKoreanCharSubsetUtf32beBom); // get the first character Expect.equals(testKoreanCharSubset.charCodes[0], - koreanDecoder.iterator().next()); + koreanDecoder.iterator.first); // get the whole translation using the Iterable interface Expect.stringEquals(testKoreanCharSubset, new String.fromCharCodes(new List.from(koreanDecoder))); diff --git a/utils/tests/string_encoding/utf8_test.dart b/utils/tests/string_encoding/utf8_test.dart index 25729d6f649..596626e0c29 100755 --- a/utils/tests/string_encoding/utf8_test.dart +++ b/utils/tests/string_encoding/utf8_test.dart @@ -459,15 +459,14 @@ class Utf8Tests extends TestClass { void testIterableMethods() { IterableUtf8Decoder englishDecoder = decodeUtf8AsIterable(testEnglishUtf8); // get the first character - Expect.equals(testEnglishUtf8[0], englishDecoder.iterator().next()); + Expect.equals(testEnglishUtf8[0], englishDecoder.first); // get the whole translation using the Iterable interface Expect.stringEquals(testEnglishPhrase, new String.fromCharCodes(new List.from(englishDecoder))); IterableUtf8Decoder kataDecoder = decodeUtf8AsIterable(testKatakanaUtf8); // get the first character - Expect.equals(testKatakanaPhrase.charCodes[0], - kataDecoder.iterator().next()); + Expect.equals(testKatakanaPhrase.charCodes[0], kataDecoder.first); // get the whole translation using the Iterable interface Expect.stringEquals(testKatakanaPhrase, new String.fromCharCodes(new List.from(kataDecoder)));