OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart._collection.dev; | 5 part of dart._collection.dev; |
6 | 6 |
7 /** | 7 /** |
8 * Temporary move `toString` methods into this class. | 8 * Temporary move `toString` methods into this class. |
9 */ | 9 */ |
10 class ToString { | 10 class ToString { |
11 // TODO(jjb): visiting list should be an identityHashSet when it exists | 11 // TODO(jjb): visiting list should be an identityHashSet when it exists |
12 | 12 |
13 /** | 13 /** |
14 * Returns a string representing the specified collection. If the | 14 * Returns a string representing the specified iterable. If the |
15 * collection is a [List], the returned string looks like this: | 15 * iterable is a [List], the returned string looks like this: |
16 * [:'[element0, element1, ... elementN]':]. The value returned by its | 16 * [:'[element0, element1, ... elementN]':]. The value returned by its |
17 * [toString] method is used to represent each element. If the specified | 17 * [toString] method is used to represent each element. If the specified |
18 * collection is not a list, the returned string looks like this: | 18 * iterable is not a list, the returned string looks like this: |
19 * [:{element0, element1, ... elementN}:]. In other words, the strings | 19 * [:{element0, element1, ... elementN}:]. In other words, the strings |
20 * returned for lists are surrounded by square brackets, while the strings | 20 * returned for lists are surrounded by square brackets, while the strings |
21 * returned for other collections are surrounded by curly braces. | 21 * returned for other iterables are surrounded by curly braces. |
22 * | 22 * |
23 * If the specified collection contains a reference to itself, either | 23 * If the specified iterable contains a reference to itself, either |
24 * directly or indirectly through other collections or maps, the contained | 24 * directly or indirectly through other iterables or maps, the contained |
25 * reference is rendered as [:'[...]':] if it is a list, or [:'{...}':] if | 25 * reference is rendered as [:'[...]':] if it is a list, or [:'{...}':] if |
26 * it is not. This prevents the infinite regress that would otherwise occur. | 26 * it is not. This prevents the infinite regress that would otherwise occur. |
27 * So, for example, calling this method on a list whose sole element is a | 27 * So, for example, calling this method on a list whose sole element is a |
28 * reference to itself would return [:'[[...]]':]. | 28 * reference to itself would return [:'[[...]]':]. |
29 * | 29 * |
30 * A typical implementation of a collection's [toString] method will | 30 * A typical implementation of a iterable's [toString] method will |
31 * simply return the results of this method applied to the collection. | 31 * simply return the results of this method applied to the iterable. |
32 */ | 32 */ |
33 static String collectionToString(Collection c) { | 33 static String iterableToString(Iterable i) { |
34 var result = new StringBuffer(); | 34 var result = new StringBuffer(); |
35 _emitCollection(c, result, new List()); | 35 _emitValue(i, result, new List()); |
36 return result.toString(); | 36 return result.toString(); |
37 } | 37 } |
38 | 38 |
39 /** | 39 /** |
40 * Appends a string representing the specified collection to the specified | 40 * Appends a string representing the specified iterable to the specified |
41 * string buffer. The string is formatted as per [collectionToString]. | 41 * string buffer. The string is formatted as per [iterableToString]. |
42 * The [:visiting:] list contains references to all of the enclosing | 42 * The [:visiting:] list contains references to all of the enclosing |
43 * collections and maps (which are currently in the process of being | 43 * iterables and maps (which are currently in the process of being |
44 * emitted into [:result:]). The [:visiting:] parameter allows this method to | 44 * emitted into [:result:]). The [:visiting:] parameter allows this method to |
45 * generate a [:'[...]':] or [:'{...}':] where required. In other words, | 45 * generate a [:'[...]':] or [:'{...}':] where required. In other words, |
46 * it allows this method and [_emitMap] to identify recursive collections | 46 * it allows this method and [_emitMap] to identify recursive iterables |
47 * and maps. | 47 * and maps. |
48 */ | 48 */ |
49 static void _emitCollection(Collection c, | 49 static void _emitValue(Iterable i, |
50 StringBuffer result, | 50 StringBuffer result, |
51 List visiting) { | 51 List visiting) { |
52 visiting.add(c); | 52 visiting.add(i); |
53 bool isList = c is List; | 53 bool isList = i is List; |
54 result.write(isList ? '[' : '{'); | 54 result.write(isList ? '[' : '{'); |
55 | 55 |
56 bool first = true; | 56 bool first = true; |
57 for (var e in c) { | 57 for (var e in i) { |
58 if (!first) { | 58 if (!first) { |
59 result.write(', '); | 59 result.write(', '); |
60 } | 60 } |
61 first = false; | 61 first = false; |
62 _emitObject(e, result, visiting); | 62 _emitObject(e, result, visiting); |
63 } | 63 } |
64 | 64 |
65 result.write(isList ? ']' : '}'); | 65 result.write(isList ? ']' : '}'); |
66 visiting.removeLast(); | 66 visiting.removeLast(); |
67 } | 67 } |
68 | 68 |
69 /** | 69 /** |
70 * Appends a string representing the specified object to the specified | 70 * Appends a string representing the specified object to the specified |
71 * string buffer. If the object is a [Collection] or [Map], it is formatted | 71 * string buffer. If the object is a [iterable] or [Map], it is formatted |
72 * as per [collectionToString] or [mapToString]; otherwise, it is formatted | 72 * as per [iterableToString] or [mapToString]; otherwise, it is formatted |
73 * by invoking its own [toString] method. | 73 * by invoking its own [toString] method. |
74 * | 74 * |
75 * The [:visiting:] list contains references to all of the enclosing | 75 * The [:visiting:] list contains references to all of the enclosing |
76 * collections and maps (which are currently in the process of being | 76 * collections and maps (which are currently in the process of being |
77 * emitted into [:result:]). The [:visiting:] parameter allows this method | 77 * emitted into [:result:]). The [:visiting:] parameter allows this method |
78 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, | 78 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, |
79 * it allows this method and [_emitCollection] to identify recursive maps | 79 * it allows this method and [_emitCollection] to identify recursive maps |
80 * and collections. | 80 * and collections. |
81 */ | 81 */ |
82 static void _emitObject(Object o, StringBuffer result, List visiting) { | 82 static void _emitObject(Object o, StringBuffer result, List visiting) { |
83 if (o is Collection) { | 83 if (o is Iterable) { |
84 if (_containsRef(visiting, o)) { | 84 if (_containsRef(visiting, o)) { |
85 result.write(o is List ? '[...]' : '{...}'); | 85 result.write(o is List ? '[...]' : '{...}'); |
86 } else { | 86 } else { |
87 _emitCollection(o, result, visiting); | 87 _emitValue(o, result, visiting); |
88 } | 88 } |
89 } else if (o is Map) { | 89 } else if (o is Map) { |
90 if (_containsRef(visiting, o)) { | 90 if (_containsRef(visiting, o)) { |
91 result.write('{...}'); | 91 result.write('{...}'); |
92 } else { | 92 } else { |
93 _emitMap(o, result, visiting); | 93 _emitPair(o, result, visiting); |
94 } | 94 } |
95 } else { // o is neither a collection nor a map | 95 } else { // o is neither a collection nor a map |
96 result.write(o); | 96 result.write(o); |
97 } | 97 } |
98 } | 98 } |
99 | 99 |
100 /** | 100 /** |
101 * Returns true if the specified collection contains the specified object | 101 * Returns true if the specified collection contains the specified object |
102 * reference. | 102 * reference. |
103 */ | 103 */ |
104 static _containsRef(Collection c, Object ref) { | 104 static _containsRef(Iterable i, Object ref) { |
105 for (var e in c) { | 105 for (var e in i) { |
106 if (identical(e, ref)) return true; | 106 if (identical(e, ref)) return true; |
107 } | 107 } |
108 return false; | 108 return false; |
109 } | 109 } |
110 | 110 |
111 /** | 111 /** |
112 * Returns a string representing the specified map. The returned string | 112 * Returns a string representing the specified map. The returned string |
113 * looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':]. | 113 * looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':]. |
114 * The value returned by its [toString] method is used to represent each | 114 * The value returned by its [toString] method is used to represent each |
115 * key or value. | 115 * key or value. |
116 * | 116 * |
117 * If the map collection contains a reference to itself, either | 117 * If the map collection contains a reference to itself, either |
118 * directly as a key or value, or indirectly through other collections | 118 * directly as a key or value, or indirectly through other collections |
119 * or maps, the contained reference is rendered as [:'{...}':]. This | 119 * or maps, the contained reference is rendered as [:'{...}':]. This |
120 * prevents the infinite regress that would otherwise occur. So, for example, | 120 * prevents the infinite regress that would otherwise occur. So, for example, |
121 * calling this method on a map whose sole entry maps the string key 'me' | 121 * calling this method on a map whose sole entry maps the string key 'me' |
122 * to a reference to the map would return [:'{me: {...}}':]. | 122 * to a reference to the map would return [:'{me: {...}}':]. |
123 * | 123 * |
124 * A typical implementation of a map's [toString] method will | 124 * A typical implementation of a map's [toString] method will |
125 * simply return the results of this method applied to the collection. | 125 * simply return the results of this method applied to the collection. |
126 */ | 126 */ |
127 static String mapToString(Map m) { | 127 static String mapToString(Map m) { |
128 var result = new StringBuffer(); | 128 var result = new StringBuffer(); |
129 _emitMap(m, result, new List()); | 129 _emitPair(m, result, new List()); |
130 return result.toString(); | 130 return result.toString(); |
131 } | 131 } |
132 | 132 |
133 /** | 133 /** |
134 * Appends a string representing the specified map to the specified | 134 * Appends a string representing the specified map to the specified |
135 * string buffer. The string is formatted as per [mapToString]. | 135 * string buffer. The string is formatted as per [mapToString]. |
136 * The [:visiting:] list contains references to all of the enclosing | 136 * The [:visiting:] list contains references to all of the enclosing |
137 * collections and maps (which are currently in the process of being | 137 * collections and maps (which are currently in the process of being |
138 * emitted into [:result:]). The [:visiting:] parameter allows this method | 138 * emitted into [:result:]). The [:visiting:] parameter allows this method |
139 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, | 139 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, |
140 * it allows this method and [_emitCollection] to identify recursive maps | 140 * it allows this method and [_emitCollection] to identify recursive maps |
141 * and collections. | 141 * and collections. |
142 */ | 142 */ |
143 static void _emitMap(Map m, StringBuffer result, List visiting) { | 143 static void _emitPair(Map m, StringBuffer result, List visiting) { |
144 visiting.add(m); | 144 visiting.add(m); |
145 result.write('{'); | 145 result.write('{'); |
146 | 146 |
147 bool first = true; | 147 bool first = true; |
148 m.forEach((k, v) { | 148 m.forEach((k, v) { |
149 if (!first) { | 149 if (!first) { |
150 result.write(', '); | 150 result.write(', '); |
151 } | 151 } |
152 first = false; | 152 first = false; |
153 _emitObject(k, result, visiting); | 153 _emitObject(k, result, visiting); |
154 result.write(': '); | 154 result.write(': '); |
155 _emitObject(v, result, visiting); | 155 _emitObject(v, result, visiting); |
156 }); | 156 }); |
157 | 157 |
158 result.write('}'); | 158 result.write('}'); |
159 visiting.removeLast(); | 159 visiting.removeLast(); |
160 } | 160 } |
161 } | 161 } |
OLD | NEW |