OLD | NEW |
| (Empty) |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 import 'dart:io'; | |
6 | |
7 // By convention: | |
8 // | |
9 // T: generic type of typedef. | |
10 // A: generic type of returned function. | |
11 // B: generic type of function. | |
12 // | |
13 // Example: | |
14 // typedef F<T>: Function<A> Function<B>(); | |
15 // | |
16 // We only use: Function, List, int (and function types). | |
17 // We import 'dart:core' directly and with prefix 'core'. | |
18 | |
19 abstract class Printable { | |
20 /// Builds a descriptive string that can be used as an identifier. | |
21 /// | |
22 /// The string is mainly used for disambiguation, and not for its readability. | |
23 void writeIdentifier(StringBuffer buffer); | |
24 } | |
25 | |
26 abstract class TypeLike implements Printable { | |
27 /// Prints `this` as valid Dart code for a Type. | |
28 void writeType(StringBuffer buffer); | |
29 | |
30 /// Whether this instance uses T in some way. | |
31 bool get usesT; | |
32 } | |
33 | |
34 /// Provides a unique integer for every parameter in a function. | |
35 int parameterNameCounter = 0; | |
36 | |
37 /// Whether `T` should be replaced with `int`. | |
38 bool shouldReplaceTWithInt = false; | |
39 | |
40 class Parameter implements Printable { | |
41 final TypeLike type; | |
42 final String name; | |
43 | |
44 Parameter(this.type, this.name); | |
45 | |
46 // Type or name can be null. | |
47 @override | |
48 writeIdentifier(buffer) { | |
49 if (type == null) { | |
50 buffer.write("null"); | |
51 } else { | |
52 type.writeIdentifier(buffer); | |
53 } | |
54 buffer.write("_"); | |
55 buffer.write(name); | |
56 } | |
57 | |
58 void writeType(StringBuffer buffer) { | |
59 assert(type != null || name != null); | |
60 if (name == null) { | |
61 type.writeType(buffer); | |
62 } else if (type == null) { | |
63 buffer.write(name); | |
64 } else { | |
65 type.writeType(buffer); | |
66 buffer.write(" "); | |
67 buffer.write(name); | |
68 } | |
69 } | |
70 | |
71 void writeInFunction(StringBuffer buffer) { | |
72 assert(type != null || name != null); | |
73 if (name == null) { | |
74 type.writeType(buffer); | |
75 buffer.write(" x"); | |
76 buffer.write(parameterNameCounter++); | |
77 } else if (type == null) { | |
78 buffer.write(name); | |
79 } else { | |
80 type.writeType(buffer); | |
81 buffer.write(" "); | |
82 buffer.write(name); | |
83 } | |
84 } | |
85 | |
86 bool operator ==(other) { | |
87 return other is Parameter && name == other.name && type == other.type; | |
88 } | |
89 | |
90 int get hashCode { | |
91 return ((name.hashCode * 37) ^ type.hashCode) & 0xFFFFFFFF; | |
92 } | |
93 | |
94 bool get usesT => type?.usesT == true; | |
95 } | |
96 | |
97 class GenericParameter implements TypeLike { | |
98 final String name; | |
99 final TypeLike bound; | |
100 | |
101 GenericParameter(this.name, [this.bound]); | |
102 | |
103 // Bound may be null. | |
104 @override | |
105 writeIdentifier(buffer) { | |
106 buffer.write(name); | |
107 buffer.write("_"); | |
108 if (bound == null) { | |
109 buffer.write("null"); | |
110 } else { | |
111 bound.writeIdentifier(buffer); | |
112 } | |
113 } | |
114 | |
115 @override | |
116 writeType(buffer) { | |
117 buffer.write(name); | |
118 if (bound != null) { | |
119 buffer.write(" extends "); | |
120 bound.writeType(buffer); | |
121 } | |
122 } | |
123 | |
124 bool operator ==(other) { | |
125 return other is GenericParameter && | |
126 name == other.name && | |
127 bound == other.bound; | |
128 } | |
129 | |
130 int get hashCode { | |
131 return ((name.hashCode * 23) ^ bound.hashCode) & 0xFFFFFFFF; | |
132 } | |
133 | |
134 bool get usesT { | |
135 return bound?.usesT == true; | |
136 } | |
137 } | |
138 | |
139 void _describeList(StringBuffer buffer, List<Printable> list) { | |
140 if (list == null) { | |
141 buffer.write("0"); | |
142 return; | |
143 } | |
144 buffer.write(list.length.toString()); | |
145 buffer.write("_"); | |
146 for (int i = 0; i < list.length; i++) { | |
147 if (i != 0) buffer.write("_"); | |
148 list[i].writeIdentifier(buffer); | |
149 } | |
150 } | |
151 | |
152 void _writeTypes(StringBuffer buffer, List<TypeLike> list, | |
153 [String prefix = "", String postfix = ""]) { | |
154 if (list == null || list.isEmpty) return; | |
155 buffer.write(prefix); | |
156 for (int i = 0; i < list.length; i++) { | |
157 if (i != 0) buffer.write(", "); | |
158 list[i].writeType(buffer); | |
159 } | |
160 buffer.write(postfix); | |
161 } | |
162 | |
163 void _writeParameters( | |
164 StringBuffer buffer, List<Parameter> list, bool inFunction, | |
165 [String prefix = "", String postfix = ""]) { | |
166 if (list == null || list.isEmpty) return; | |
167 buffer.write(prefix); | |
168 for (int i = 0; i < list.length; i++) { | |
169 if (i != 0) buffer.write(", "); | |
170 if (inFunction) { | |
171 list[i].writeInFunction(buffer); | |
172 } else { | |
173 list[i].writeType(buffer); | |
174 } | |
175 } | |
176 buffer.write(postfix); | |
177 } | |
178 | |
179 bool _listUsesT(List elements) { | |
180 if (elements == null) return false; | |
181 return elements.any((p) => p.usesT); | |
182 } | |
183 | |
184 bool _listEquals(List list1, List list2) { | |
185 if (list1 == list2) return true; // Also covers both being null. | |
186 if (list1 == null || list2 == null) return false; | |
187 for (int i = 0; i < list1.length; i++) { | |
188 if (list1[i] != list2[i]) return false; | |
189 } | |
190 return true; | |
191 } | |
192 | |
193 int _listHash(List list) { | |
194 if (list == null) return null.hashCode; | |
195 int result = 71; | |
196 for (int i = 0; i < list.length; i++) { | |
197 result = ((result * 11) ^ list[i].hashCode) & 0xFFFFFFFF; | |
198 } | |
199 return result; | |
200 } | |
201 | |
202 class FunctionType implements TypeLike { | |
203 final TypeLike returnType; | |
204 final List<GenericParameter> generic; | |
205 final List<Parameter> required; | |
206 final List<Parameter> optional; | |
207 final List<Parameter> named; | |
208 | |
209 FunctionType(this.returnType, this.generic, this.required, | |
210 [this.optional, this.named]); | |
211 | |
212 @override | |
213 writeIdentifier(buffer) { | |
214 buffer.write("Fun_"); | |
215 if (returnType == null) { | |
216 buffer.write("null"); | |
217 } else { | |
218 returnType.writeIdentifier(buffer); | |
219 } | |
220 buffer.write("_"); | |
221 _describeList(buffer, generic); | |
222 buffer.write("_"); | |
223 _describeList(buffer, required); | |
224 buffer.write("_"); | |
225 _describeList(buffer, optional); | |
226 buffer.write("_"); | |
227 _describeList(buffer, named); | |
228 } | |
229 | |
230 @override | |
231 writeType(buffer) { | |
232 if (returnType != null) { | |
233 returnType.writeType(buffer); | |
234 buffer.write(" "); | |
235 } | |
236 buffer.write("Function"); | |
237 if (generic != null) _writeTypes(buffer, generic, "<", ">"); | |
238 buffer.write("("); | |
239 bool notInFunction = true; | |
240 _writeParameters(buffer, required, notInFunction); | |
241 if ((optional != null || named != null) && | |
242 required != null && | |
243 required.isNotEmpty) { | |
244 buffer.write(", "); | |
245 } | |
246 _writeParameters(buffer, optional, notInFunction, "[", "]"); | |
247 _writeParameters(buffer, named, notInFunction, "{", "}"); | |
248 buffer.write(")"); | |
249 } | |
250 | |
251 /// Writes this type as if it was a function. | |
252 void writeFunction(StringBuffer buffer, String name, {bool replaceT: true}) { | |
253 shouldReplaceTWithInt = replaceT; | |
254 parameterNameCounter = 0; | |
255 | |
256 if (returnType != null) { | |
257 returnType.writeType(buffer); | |
258 buffer.write(" "); | |
259 } | |
260 | |
261 buffer.write(name); | |
262 if (generic != null) _writeTypes(buffer, generic, "<", ">"); | |
263 buffer.write("("); | |
264 bool inFunction = true; | |
265 _writeParameters(buffer, required, inFunction); | |
266 if ((optional != null || named != null) && | |
267 required != null && | |
268 required.isNotEmpty) { | |
269 buffer.write(", "); | |
270 } | |
271 _writeParameters(buffer, optional, inFunction, "[", "]"); | |
272 _writeParameters(buffer, named, inFunction, "{", "}"); | |
273 buffer.write(") => null;"); | |
274 | |
275 shouldReplaceTWithInt = false; | |
276 } | |
277 | |
278 bool operator ==(other) { | |
279 return returnType == other.returnType && | |
280 _listEquals(generic, other.generic) && | |
281 _listEquals(required, other.required) && | |
282 _listEquals(optional, other.optional) && | |
283 _listEquals(named, other.named); | |
284 } | |
285 | |
286 int get hashCode { | |
287 return ((returnType.hashCode * 13) ^ | |
288 (_listHash(generic) * 17) ^ | |
289 (_listHash(required) * 53) ^ | |
290 (_listHash(optional) ^ 31) ^ | |
291 (_listHash(named) * 87)) & | |
292 0xFFFFFFFF; | |
293 } | |
294 | |
295 bool get usesT { | |
296 return returnType?.usesT == true || | |
297 [generic, required, optional, named].any(_listUsesT); | |
298 } | |
299 } | |
300 | |
301 class NominalType implements TypeLike { | |
302 final String prefix; | |
303 final String name; | |
304 final List<TypeLike> generic; | |
305 | |
306 NominalType(this.name, [this.prefix, this.generic]); | |
307 | |
308 @override | |
309 writeIdentifier(buffer) { | |
310 buffer.write(prefix); | |
311 buffer.write("_"); | |
312 buffer.write(name); | |
313 _describeList(buffer, generic); | |
314 } | |
315 | |
316 @override | |
317 writeType(buffer) { | |
318 if (prefix != null && prefix != "") { | |
319 buffer.write(prefix); | |
320 buffer.write("."); | |
321 } | |
322 if (shouldReplaceTWithInt && name == "T") { | |
323 buffer.write("int"); | |
324 } else { | |
325 buffer.write(name); | |
326 } | |
327 _writeTypes(buffer, generic, "<", ">"); | |
328 } | |
329 | |
330 bool operator ==(other) { | |
331 return other is NominalType && prefix == other.prefix && name == other.name; | |
332 } | |
333 | |
334 int get hashCode { | |
335 return ((prefix.hashCode * 37) ^ name.hashCode) & 0xFFFFFFFF; | |
336 } | |
337 | |
338 bool get usesT => name == "T" || _listUsesT(generic); | |
339 } | |
340 | |
341 List<FunctionType> buildFunctionTypes() { | |
342 List<GenericParameter> as = [ | |
343 new GenericParameter("A"), | |
344 // new GenericParameter("A", new NominalType("int")), | |
345 // new GenericParameter("A", new NominalType("int", "core")), | |
346 ]; | |
347 List<GenericParameter> bs = [ | |
348 // new GenericParameter("B"), | |
349 // new GenericParameter("B", new NominalType("int")), | |
350 new GenericParameter("B", new NominalType("int", "core")), | |
351 ]; | |
352 List<TypeLike> basicTypes = [ | |
353 new NominalType("int"), | |
354 // new NominalType("int", "core"), | |
355 // new NominalType("List"), | |
356 // new NominalType("List", "core"), | |
357 new NominalType("Function"), | |
358 new NominalType("List", "", [new NominalType("Function")]), | |
359 new NominalType("List", "core", [new NominalType("int", "core")]), | |
360 new NominalType("List", "", [new NominalType("T")]), | |
361 // new NominalType("List", "", [new NominalType("Function")]), | |
362 ]; | |
363 | |
364 List<TypeLike> basicsPlusNull = [ | |
365 basicTypes, | |
366 <TypeLike>[null] | |
367 ].expand((x) => x).toList(); | |
368 | |
369 List<TypeLike> basicsPlusNullPlusVoid = [ | |
370 basicsPlusNull, | |
371 [new NominalType("void")], | |
372 ].expand((x) => x).toList(); | |
373 | |
374 List<TypeLike> basicsPlusNullPlusB = [ | |
375 basicsPlusNull, | |
376 [ | |
377 new NominalType("B"), | |
378 new NominalType("List", "", [new NominalType("B")]) | |
379 ] | |
380 ].expand((x) => x).toList(); | |
381 | |
382 List<TypeLike> basicsPlusNullPlusBPlusVoid = [ | |
383 basicsPlusNullPlusB, | |
384 [new NominalType("void")], | |
385 ].expand((x) => x).toList(); | |
386 | |
387 List<TypeLike> basicsPlusNullPlusA = [ | |
388 basicsPlusNull, | |
389 [ | |
390 new NominalType("A"), | |
391 new NominalType("List", "", [new NominalType("A")]) | |
392 ] | |
393 ].expand((x) => x).toList(); | |
394 | |
395 List<TypeLike> basicsPlusNullPlusAPlusVoid = [ | |
396 basicsPlusNullPlusA, | |
397 [new NominalType("void")], | |
398 ].expand((x) => x).toList(); | |
399 | |
400 List<TypeLike> buildFunctionTypes(TypeLike returnType, TypeLike parameterType, | |
401 [List<GenericParameter> generics, | |
402 bool generateMoreCombinations = false]) { | |
403 List<TypeLike> result = []; | |
404 | |
405 if (parameterType == null) { | |
406 // int Function(). | |
407 result.add(new FunctionType(returnType, generics, null)); | |
408 return result; | |
409 } | |
410 | |
411 // int Function(int x). | |
412 result.add(new FunctionType( | |
413 returnType, generics, [new Parameter(parameterType, "x")])); | |
414 | |
415 if (!generateMoreCombinations) return result; | |
416 | |
417 // int Function([int x]). | |
418 result.add(new FunctionType( | |
419 returnType, generics, null, [new Parameter(parameterType, "x")])); | |
420 // int Function(int, [int x]) | |
421 result.add(new FunctionType( | |
422 returnType, | |
423 generics, | |
424 [new Parameter(new NominalType("int"), null)], | |
425 [new Parameter(parameterType, "x")])); | |
426 // int Function(int x, [int x]) | |
427 result.add(new FunctionType( | |
428 returnType, | |
429 generics, | |
430 [new Parameter(new NominalType("int"), "y")], | |
431 [new Parameter(parameterType, "x")])); | |
432 // int Function(int); | |
433 result.add(new FunctionType( | |
434 returnType, generics, [new Parameter(parameterType, null)])); | |
435 // int Function([int]); | |
436 result.add(new FunctionType( | |
437 returnType, generics, null, [new Parameter(parameterType, null)])); | |
438 // int Function(int, [int]) | |
439 result.add(new FunctionType( | |
440 returnType, | |
441 generics, | |
442 [new Parameter(new NominalType("int"), null)], | |
443 [new Parameter(parameterType, null)])); | |
444 // int Function(int x, [int]) | |
445 result.add(new FunctionType( | |
446 returnType, | |
447 generics, | |
448 [new Parameter(new NominalType("int"), "x")], | |
449 [new Parameter(parameterType, null)])); | |
450 // int Function({int x}). | |
451 result.add(new FunctionType(returnType, generics, null, null, | |
452 [new Parameter(parameterType, "x")])); | |
453 // int Function(int, {int x}) | |
454 result.add(new FunctionType( | |
455 returnType, | |
456 generics, | |
457 [new Parameter(new NominalType("int"), null)], | |
458 null, | |
459 [new Parameter(parameterType, "x")])); | |
460 // int Function(int x, {int x}) | |
461 result.add(new FunctionType( | |
462 returnType, | |
463 generics, | |
464 [new Parameter(new NominalType("int"), "y")], | |
465 null, | |
466 [new Parameter(parameterType, "x")])); | |
467 return result; | |
468 } | |
469 | |
470 // The "smaller" function types. May also be used non-nested. | |
471 List<TypeLike> functionTypes = []; | |
472 | |
473 for (TypeLike returnType in basicsPlusNullPlusVoid) { | |
474 for (TypeLike parameterType in basicsPlusNull) { | |
475 bool generateMoreCombinations = true; | |
476 functionTypes.addAll(buildFunctionTypes( | |
477 returnType, parameterType, null, generateMoreCombinations)); | |
478 } | |
479 } | |
480 | |
481 // These use `B` from the generic type of the enclosing function. | |
482 List<TypeLike> returnFunctionTypesB = []; | |
483 for (TypeLike returnType in basicsPlusNullPlusBPlusVoid) { | |
484 TypeLike parameterType = new NominalType("B"); | |
485 returnFunctionTypesB.addAll(buildFunctionTypes(returnType, parameterType)); | |
486 } | |
487 for (TypeLike parameterType in basicsPlusNull) { | |
488 TypeLike returnType = new NominalType("B"); | |
489 returnFunctionTypesB.addAll(buildFunctionTypes(returnType, parameterType)); | |
490 } | |
491 | |
492 for (TypeLike returnType in basicsPlusNullPlusAPlusVoid) { | |
493 for (TypeLike parameterType in basicsPlusNullPlusA) { | |
494 for (GenericParameter a in as) { | |
495 functionTypes | |
496 .addAll(buildFunctionTypes(returnType, parameterType, [a])); | |
497 } | |
498 } | |
499 } | |
500 | |
501 List<TypeLike> types = []; | |
502 types.addAll(functionTypes); | |
503 | |
504 // Now add some higher-order function types. | |
505 for (TypeLike returnType in functionTypes) { | |
506 types.addAll(buildFunctionTypes(returnType, null)); | |
507 types.addAll(buildFunctionTypes(returnType, new NominalType("int"))); | |
508 for (var b in bs) { | |
509 types.addAll(buildFunctionTypes(returnType, null, [b])); | |
510 types.addAll(buildFunctionTypes(returnType, new NominalType("int"), [b])); | |
511 } | |
512 } | |
513 for (TypeLike returnType in returnFunctionTypesB) { | |
514 for (var b in bs) { | |
515 types.addAll(buildFunctionTypes(returnType, null, [b])); | |
516 types.addAll(buildFunctionTypes(returnType, new NominalType("int"), [b])); | |
517 } | |
518 } | |
519 | |
520 return types; | |
521 } | |
522 | |
523 final String HEADER = """ | |
524 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
525 // for details. All rights reserved. Use of this source code is governed by a | |
526 // BSD-style license that can be found in the LICENSE file. | |
527 | |
528 // GENERATED - DON'T EDIT. | |
529 // GENERATED - DON'T EDIT. | |
530 // GENERATED - DON'T EDIT. | |
531 // GENERATED - DON'T EDIT. | |
532 // GENERATED - DON'T EDIT. | |
533 // GENERATED - DON'T EDIT. | |
534 // GENERATED - DON'T EDIT. | |
535 // GENERATED - DON'T EDIT. | |
536 | |
537 import 'dart:core'; | |
538 import 'dart:core' as core; | |
539 import 'package:expect/expect.dart'; | |
540 | |
541 @NoInline() | |
542 @AssumeDynamic() | |
543 confuse(f) => f; | |
544 | |
545 final bool inCheckedMode = | |
546 (() { bool result = false; assert(result = true); return result; })(); | |
547 """; | |
548 | |
549 | |
550 class Unit { | |
551 final String name; | |
552 final StringBuffer typedefs = new StringBuffer(); | |
553 final StringBuffer globals = new StringBuffer(); | |
554 final StringBuffer tests = new StringBuffer(); | |
555 final StringBuffer fields = new StringBuffer(); | |
556 final StringBuffer statics = new StringBuffer(); | |
557 final StringBuffer testMethods = new StringBuffer(); | |
558 final StringBuffer methods = new StringBuffer(); | |
559 | |
560 Unit(this.name); | |
561 | |
562 void write(StringBuffer buffer) { | |
563 buffer.write(""" | |
564 $HEADER | |
565 | |
566 $typedefs | |
567 | |
568 $globals | |
569 | |
570 class $name<T> { | |
571 final bool tIsBool; | |
572 final bool tIsInt; | |
573 final bool tIsDynamic; | |
574 | |
575 $fields | |
576 | |
577 $name({this.tIsBool: false, this.tIsInt: false}) | |
578 : tIsDynamic = !tIsBool && !tIsInt; | |
579 | |
580 $methods | |
581 | |
582 runTests() {\n$tests } | |
583 | |
584 $testMethods | |
585 } | |
586 | |
587 void main() { | |
588 new $name().runTests(); | |
589 new $name<int>(tIsInt: true).runTests(); | |
590 new $name<bool>(tIsBool: true).runTests(); | |
591 } | |
592 """); | |
593 } | |
594 } | |
595 | |
596 | |
597 final TEST_METHOD_HEADER = """ | |
598 void #testName() { | |
599 // #typeCode"""; | |
600 | |
601 // Tests that apply for every type. | |
602 final COMMON_TESTS_TEMPLATE = """ | |
603 Expect.isTrue(#staticFunName is #typeName); | |
604 Expect.isTrue(confuse(#staticFunName) is #typeName); | |
605 // In checked mode, verifies the type. | |
606 #typeCode #localName; | |
607 // The static function #staticFunName sets `T` to `int`. | |
608 if (!tIsBool) { | |
609 #fieldName = #staticFunName as dynamic; | |
610 #localName = #staticFunName as dynamic; | |
611 #fieldName = confuse(#staticFunName); | |
612 #localName = confuse(#staticFunName); | |
613 } | |
614 | |
615 Expect.isTrue(#methodFunName is #typeName); | |
616 Expect.isTrue(#methodFunName is #typeCode); | |
617 Expect.isTrue(confuse(#methodFunName) is #typeName); | |
618 // In checked mode, verifies the type. | |
619 #fieldName = #methodFunName; | |
620 #localName = #methodFunName; | |
621 #fieldName = confuse(#methodFunName); | |
622 #localName = confuse(#methodFunName);"""; | |
623 | |
624 // Tests that depend on the typedef "T" argument. | |
625 // | |
626 // These tests are executed when the surrounding class is instantiated with | |
627 // its generic type set to `int`, `dynamic` or `bool`. In the latter case, the | |
628 // class field `tIsBool` is set to true. | |
629 | |
630 // While the types themselves are not affected by the class` `T`, the methods | |
631 // of the class may use `T`: | |
632 // | |
633 // For example: | |
634 // class A<T> { | |
635 // f(List<T> x) {} | |
636 // } | |
637 final TYPEDEF_T_TESTS_TEMPLATE = """ | |
638 if (!tIsBool) { | |
639 Expect.isTrue(#staticFunName is #typeName<int>); | |
640 Expect.isFalse(#staticFunName is #typeName<bool>); | |
641 Expect.isTrue(confuse(#staticFunName) is #typeName<int>); | |
642 Expect.isFalse(confuse(#staticFunName) is #typeName<bool>); | |
643 Expect.equals(tIsDynamic, #methodFunName is #typeName<bool>); | |
644 Expect.equals(tIsDynamic, confuse(#methodFunName) is #typeName<bool>); | |
645 } else { | |
646 if (inCheckedMode) { | |
647 Expect.throws(() { #fieldName = (#staticFunName as dynamic); }); | |
648 Expect.throws(() { #fieldName = confuse(#staticFunName); }); | |
649 #typeCode #localName; | |
650 Expect.throws(() { #localName = (#staticFunName as dynamic); }); | |
651 Expect.throws(() { #localName = confuse(#staticFunName); }); | |
652 } | |
653 #typeCode #localName = #methodFunName; | |
654 // In checked mode, verifies the type. | |
655 #fieldName = #methodFunName; | |
656 #fieldName = confuse(#methodFunName); | |
657 }"""; | |
658 | |
659 final TEST_METHOD_FOOTER = " }"; | |
660 | |
661 String createTypeName(int id) => "F$id"; | |
662 String createStaticFunName(int id) => "f$id"; | |
663 String createMethodFunName(int id) => "m$id"; | |
664 String createFieldName(int id) => "x$id"; | |
665 String createLocalName(int id) => "l$id"; | |
666 String createTestName(int id) => "test${createTypeName(id)}"; | |
667 | |
668 String createTypeCode(FunctionType type) { | |
669 StringBuffer typeBuffer = new StringBuffer(); | |
670 type.writeType(typeBuffer); | |
671 return typeBuffer.toString(); | |
672 } | |
673 String createStaticFunCode(FunctionType type, int id) { | |
674 StringBuffer staticFunBuffer = new StringBuffer(); | |
675 type.writeFunction(staticFunBuffer, createStaticFunName(id)); | |
676 return staticFunBuffer.toString(); | |
677 } | |
678 | |
679 String createMethodFunCode(FunctionType type, int id) { | |
680 StringBuffer methodFunBuffer = new StringBuffer(); | |
681 type.writeFunction(methodFunBuffer, createMethodFunName(id), replaceT: false); | |
682 return methodFunBuffer.toString(); | |
683 } | |
684 | |
685 String createTestMethodFunCode(FunctionType type, String typeCode, int id) { | |
686 String fillTemplate(String template, int id) { | |
687 var result = template | |
688 .replaceAll("#typeName", createTypeName(id)) | |
689 .replaceAll("#staticFunName", createStaticFunName(id)) | |
690 .replaceAll("#methodFunName", createMethodFunName(id)) | |
691 .replaceAll("#fieldName", createFieldName(id)) | |
692 .replaceAll("#localName", createLocalName(id)) | |
693 .replaceAll("#testName", createTestName(id)) | |
694 .replaceAll("#typeCode", typeCode); | |
695 assert(!result.contains("#")); | |
696 return result; | |
697 } | |
698 | |
699 String commonTests = fillTemplate(COMMON_TESTS_TEMPLATE, id); | |
700 String genericTTests = ""; | |
701 if (type.usesT) { | |
702 genericTTests = fillTemplate(TYPEDEF_T_TESTS_TEMPLATE, id); | |
703 } | |
704 return """ | |
705 ${fillTemplate(TEST_METHOD_HEADER, id)} | |
706 $commonTests | |
707 $genericTTests | |
708 $TEST_METHOD_FOOTER | |
709 """; | |
710 } | |
711 | |
712 void generateTests() { | |
713 // Keep methods and classes smaller by distributing over several different | |
714 // classes. | |
715 List<Unit> units = []; | |
716 for (int i = 0; i < 100; i++) { | |
717 units.add(new Unit("U$i")); | |
718 } | |
719 | |
720 var types = buildFunctionTypes(); | |
721 | |
722 int typeCounter = 0; | |
723 types.forEach((FunctionType type) { | |
724 Unit unit = units[typeCounter % units.length]; | |
725 | |
726 String typeName = createTypeName(typeCounter); | |
727 String fieldName = createFieldName(typeCounter); | |
728 String testName = createTestName(typeCounter); | |
729 | |
730 String typeCode = createTypeCode(type); | |
731 String staticFunCode = createStaticFunCode(type, typeCounter); | |
732 String methodFunCode = createMethodFunCode(type, typeCounter); | |
733 String testMethodCode = | |
734 createTestMethodFunCode(type, typeCode, typeCounter); | |
735 | |
736 | |
737 unit.typedefs.writeln("typedef $typeName<T> = $typeCode;"); | |
738 unit.globals.writeln(staticFunCode); | |
739 unit.fields.writeln(" $typeCode $fieldName;"); | |
740 unit.methods.writeln(" $methodFunCode"); | |
741 unit.testMethods.writeln("$testMethodCode"); | |
742 unit.tests.writeln(" $testName();"); | |
743 | |
744 typeCounter++; | |
745 }); | |
746 | |
747 for (int i = 0; i < units.length; i++) { | |
748 var unit = units[i]; | |
749 var buffer = new StringBuffer(); | |
750 unit.write(buffer); | |
751 var path = Platform.script.resolve("function_type${i}_test.dart").path; | |
752 new File(path).writeAsStringSync(buffer.toString()); | |
753 } | |
754 } | |
755 | |
756 void printUsage() { | |
757 print(""" | |
758 Generates function type tests. | |
759 | |
760 All tests are generated in the same directory as this script. | |
761 """); | |
762 } | |
763 | |
764 void main(List<String> arguments) { | |
765 if (arguments.length != 0) { | |
766 printUsage(); | |
767 return; | |
768 } | |
769 generateTests(); | |
770 } | |
OLD | NEW |