OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library compiler_helper; | 5 library compiler_helper; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import "package:expect/expect.dart"; | 8 import "package:expect/expect.dart"; |
9 | 9 |
10 import 'package:compiler/src/elements/elements.dart' | 10 import 'package:compiler/src/elements/elements.dart' as lego; |
11 as lego; | |
12 export 'package:compiler/src/elements/elements.dart'; | 11 export 'package:compiler/src/elements/elements.dart'; |
13 | 12 |
14 import 'package:compiler/src/js_backend/js_backend.dart' | 13 import 'package:compiler/src/js_backend/js_backend.dart' as js; |
15 as js; | |
16 | 14 |
17 import 'package:compiler/src/commandline_options.dart'; | 15 import 'package:compiler/src/commandline_options.dart'; |
18 import 'package:compiler/src/common/codegen.dart'; | 16 import 'package:compiler/src/common/codegen.dart'; |
19 import 'package:compiler/src/common/resolution.dart'; | 17 import 'package:compiler/src/common/resolution.dart'; |
20 | 18 |
21 export 'package:compiler/src/diagnostics/messages.dart'; | 19 export 'package:compiler/src/diagnostics/messages.dart'; |
22 export 'package:compiler/src/diagnostics/source_span.dart'; | 20 export 'package:compiler/src/diagnostics/source_span.dart'; |
23 export 'package:compiler/src/diagnostics/spannable.dart'; | 21 export 'package:compiler/src/diagnostics/spannable.dart'; |
24 | 22 |
25 import 'package:compiler/src/types/types.dart' | 23 import 'package:compiler/src/types/types.dart' as types; |
26 as types; | 24 export 'package:compiler/src/types/types.dart' show TypeMask; |
27 export 'package:compiler/src/types/types.dart' | |
28 show TypeMask; | |
29 | 25 |
30 import 'package:compiler/src/util/util.dart'; | 26 import 'package:compiler/src/util/util.dart'; |
31 export 'package:compiler/src/util/util.dart'; | 27 export 'package:compiler/src/util/util.dart'; |
32 | 28 |
33 import 'package:compiler/src/compiler.dart' | 29 import 'package:compiler/src/compiler.dart' show Compiler; |
34 show Compiler; | |
35 | 30 |
36 export 'package:compiler/src/tree/tree.dart'; | 31 export 'package:compiler/src/tree/tree.dart'; |
37 | 32 |
38 import 'mock_compiler.dart'; | 33 import 'mock_compiler.dart'; |
39 export 'mock_compiler.dart'; | 34 export 'mock_compiler.dart'; |
40 | 35 |
41 import 'memory_compiler.dart' hide compilerFor; | 36 import 'memory_compiler.dart' hide compilerFor; |
42 | 37 |
43 import 'output_collector.dart'; | 38 import 'output_collector.dart'; |
44 export 'output_collector.dart'; | 39 export 'output_collector.dart'; |
45 | 40 |
46 /// Compile [code] and returns either the code for [entry] or, if [returnAll] is | 41 /// Compile [code] and returns either the code for [entry] or, if [returnAll] is |
47 /// true, the code for the entire program. | 42 /// true, the code for the entire program. |
48 /// | 43 /// |
49 /// If [check] is provided, it is executed on the code for [entry] before | 44 /// If [check] is provided, it is executed on the code for [entry] before |
50 /// returning. If [useMock] is `true` the [MockCompiler] is used for | 45 /// returning. If [useMock] is `true` the [MockCompiler] is used for |
51 /// compilation, otherwise the memory compiler is used. | 46 /// compilation, otherwise the memory compiler is used. |
52 Future<String> compile(String code, | 47 Future<String> compile(String code, |
53 {String entry: 'main', | 48 {String entry: 'main', |
54 bool enableTypeAssertions: false, | 49 bool enableTypeAssertions: false, |
55 bool minify: false, | 50 bool minify: false, |
56 bool analyzeAll: false, | 51 bool analyzeAll: false, |
57 bool disableInlining: true, | 52 bool disableInlining: true, |
58 bool trustJSInteropTypeAnnotations: false, | 53 bool trustJSInteropTypeAnnotations: false, |
59 bool useMock: false, | 54 bool useMock: false, |
60 void check(String generatedEntry), | 55 void check(String generatedEntry), |
61 bool returnAll: false}) async { | 56 bool returnAll: false}) async { |
62 OutputCollector outputCollector = returnAll ? new OutputCollector() : null; | 57 OutputCollector outputCollector = returnAll ? new OutputCollector() : null; |
63 if (useMock) { | 58 if (useMock) { |
64 // TODO(johnniwinther): Remove this when no longer needed by | 59 // TODO(johnniwinther): Remove this when no longer needed by |
65 // `arithmetic_simplication_test.dart`. | 60 // `arithmetic_simplication_test.dart`. |
66 MockCompiler compiler = new MockCompiler.internal( | 61 MockCompiler compiler = new MockCompiler.internal( |
67 enableTypeAssertions: enableTypeAssertions, | 62 enableTypeAssertions: enableTypeAssertions, |
68 // Type inference does not run when manually | 63 // Type inference does not run when manually |
69 // compiling a method. | 64 // compiling a method. |
70 disableTypeInference: true, | 65 disableTypeInference: true, |
71 enableMinification: minify, | 66 enableMinification: minify, |
72 disableInlining: disableInlining, | 67 disableInlining: disableInlining, |
73 trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations, | 68 trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations, |
74 outputProvider: outputCollector); | 69 outputProvider: outputCollector); |
75 await compiler.init(); | 70 await compiler.init(); |
76 compiler.parseScript(code); | 71 compiler.parseScript(code); |
77 lego.Element element = compiler.mainApp.find(entry); | 72 lego.Element element = compiler.mainApp.find(entry); |
78 if (element == null) return null; | 73 if (element == null) return null; |
79 compiler.phase = Compiler.PHASE_RESOLVING; | 74 compiler.phase = Compiler.PHASE_RESOLVING; |
80 compiler.backend.enqueueHelpers(compiler.enqueuer.resolution, | 75 compiler.backend.enqueueHelpers( |
81 compiler.globalDependencies); | 76 compiler.enqueuer.resolution, compiler.globalDependencies); |
82 compiler.processQueue(compiler.enqueuer.resolution, element); | 77 compiler.processQueue(compiler.enqueuer.resolution, element); |
83 compiler.world.populate(); | 78 compiler.world.populate(); |
84 compiler.backend.onResolutionComplete(); | 79 compiler.backend.onResolutionComplete(); |
85 ResolutionWorkItem resolutionWork = new ResolutionWorkItem(element); | 80 ResolutionWorkItem resolutionWork = new ResolutionWorkItem(element); |
86 resolutionWork.run(compiler, compiler.enqueuer.resolution); | 81 resolutionWork.run(compiler, compiler.enqueuer.resolution); |
87 CodegenWorkItem work = new CodegenWorkItem(compiler, element); | 82 CodegenWorkItem work = new CodegenWorkItem(compiler, element); |
88 compiler.phase = Compiler.PHASE_COMPILING; | 83 compiler.phase = Compiler.PHASE_COMPILING; |
89 work.run(compiler, compiler.enqueuer.codegen); | 84 work.run(compiler, compiler.enqueuer.codegen); |
90 js.JavaScriptBackend backend = compiler.backend; | 85 js.JavaScriptBackend backend = compiler.backend; |
91 String generated = backend.getGeneratedCode(element); | 86 String generated = backend.getGeneratedCode(element); |
92 if (check != null) { | 87 if (check != null) { |
93 check(generated); | 88 check(generated); |
94 } | 89 } |
95 return returnAll ? outputCollector.getOutput('', 'js') : generated; | 90 return returnAll ? outputCollector.getOutput('', 'js') : generated; |
96 } else { | 91 } else { |
97 List<String> options = <String>[ | 92 List<String> options = <String>[Flags.disableTypeInference]; |
98 Flags.disableTypeInference]; | |
99 if (enableTypeAssertions) { | 93 if (enableTypeAssertions) { |
100 options.add(Flags.enableCheckedMode); | 94 options.add(Flags.enableCheckedMode); |
101 } | 95 } |
102 if (minify) { | 96 if (minify) { |
103 options.add(Flags.minify); | 97 options.add(Flags.minify); |
104 } | 98 } |
105 if (analyzeAll) { | 99 if (analyzeAll) { |
106 options.add(Flags.analyzeAll); | 100 options.add(Flags.analyzeAll); |
107 } | 101 } |
108 if (trustJSInteropTypeAnnotations) { | 102 if (trustJSInteropTypeAnnotations) { |
109 options.add(Flags.trustJSInteropTypeAnnotations); | 103 options.add(Flags.trustJSInteropTypeAnnotations); |
110 } | 104 } |
111 | 105 |
112 if (disableInlining) { | 106 if (disableInlining) { |
113 options.add(Flags.disableInlining); | 107 options.add(Flags.disableInlining); |
114 } | 108 } |
115 | 109 |
116 Map<String, String> source; | 110 Map<String, String> source; |
117 if (entry != 'main') { | 111 if (entry != 'main') { |
118 source = {'main.dart': "$code\n\nmain() => $entry;" }; | 112 source = {'main.dart': "$code\n\nmain() => $entry;"}; |
119 } else { | 113 } else { |
120 source = {'main.dart': code}; | 114 source = {'main.dart': code}; |
121 } | 115 } |
122 | 116 |
123 CompilationResult result = await runCompiler( | 117 CompilationResult result = await runCompiler( |
124 memorySourceFiles: source, | 118 memorySourceFiles: source, |
125 options: options, | 119 options: options, |
126 outputProvider: outputCollector); | 120 outputProvider: outputCollector); |
127 Expect.isTrue(result.isSuccess); | 121 Expect.isTrue(result.isSuccess); |
128 Compiler compiler = result.compiler; | 122 Compiler compiler = result.compiler; |
129 lego.Element element = compiler.mainApp.find(entry); | 123 lego.Element element = compiler.mainApp.find(entry); |
130 js.JavaScriptBackend backend = compiler.backend; | 124 js.JavaScriptBackend backend = compiler.backend; |
131 String generated = backend.getGeneratedCode(element); | 125 String generated = backend.getGeneratedCode(element); |
132 if (check != null) { | 126 if (check != null) { |
133 check(generated); | 127 check(generated); |
134 } | 128 } |
135 return returnAll ? outputCollector.getOutput('', 'js') : generated; | 129 return returnAll ? outputCollector.getOutput('', 'js') : generated; |
136 } | 130 } |
137 } | 131 } |
138 | 132 |
139 Future<String> compileAll(String code, | 133 Future<String> compileAll(String code, |
140 {Map<String, String> coreSource, | 134 {Map<String, String> coreSource, |
141 bool disableInlining: true, | 135 bool disableInlining: true, |
142 bool trustTypeAnnotations: false, | 136 bool trustTypeAnnotations: false, |
143 bool minify: false, | 137 bool minify: false, |
144 int expectedErrors, | 138 int expectedErrors, |
145 int expectedWarnings}) { | 139 int expectedWarnings}) { |
146 Uri uri = new Uri(scheme: 'source'); | 140 Uri uri = new Uri(scheme: 'source'); |
147 OutputCollector outputCollector = new OutputCollector(); | 141 OutputCollector outputCollector = new OutputCollector(); |
148 MockCompiler compiler = compilerFor( | 142 MockCompiler compiler = compilerFor(code, uri, |
149 code, uri, coreSource: coreSource, disableInlining: disableInlining, | 143 coreSource: coreSource, |
150 minify: minify, expectedErrors: expectedErrors, | 144 disableInlining: disableInlining, |
| 145 minify: minify, |
| 146 expectedErrors: expectedErrors, |
151 trustTypeAnnotations: trustTypeAnnotations, | 147 trustTypeAnnotations: trustTypeAnnotations, |
152 expectedWarnings: expectedWarnings, | 148 expectedWarnings: expectedWarnings, |
153 outputProvider: outputCollector); | 149 outputProvider: outputCollector); |
154 compiler.diagnosticHandler = createHandler(compiler, code); | 150 compiler.diagnosticHandler = createHandler(compiler, code); |
155 return compiler.run(uri).then((compilationSucceded) { | 151 return compiler.run(uri).then((compilationSucceded) { |
156 Expect.isTrue(compilationSucceded, | 152 Expect.isTrue( |
157 'Unexpected compilation error(s): ' | 153 compilationSucceded, |
158 '${compiler.diagnosticCollector.errors}'); | 154 'Unexpected compilation error(s): ' |
| 155 '${compiler.diagnosticCollector.errors}'); |
159 return outputCollector.getOutput('', 'js'); | 156 return outputCollector.getOutput('', 'js'); |
160 }); | 157 }); |
161 } | 158 } |
162 | 159 |
163 Future compileAndCheck(String code, | 160 Future compileAndCheck(String code, String name, |
164 String name, | 161 check(MockCompiler compiler, lego.Element element), |
165 check(MockCompiler compiler, lego.Element element), | 162 {int expectedErrors, int expectedWarnings}) { |
166 {int expectedErrors, int expectedWarnings}) { | |
167 Uri uri = new Uri(scheme: 'source'); | 163 Uri uri = new Uri(scheme: 'source'); |
168 MockCompiler compiler = compilerFor(code, uri, | 164 MockCompiler compiler = compilerFor(code, uri, |
169 expectedErrors: expectedErrors, | 165 expectedErrors: expectedErrors, expectedWarnings: expectedWarnings); |
170 expectedWarnings: expectedWarnings); | |
171 return compiler.run(uri).then((_) { | 166 return compiler.run(uri).then((_) { |
172 lego.Element element = findElement(compiler, name); | 167 lego.Element element = findElement(compiler, name); |
173 return check(compiler, element); | 168 return check(compiler, element); |
174 }); | 169 }); |
175 } | 170 } |
176 | 171 |
177 Future compileSources(Map<String, String> sources, | 172 Future compileSources( |
178 check(MockCompiler compiler)) { | 173 Map<String, String> sources, check(MockCompiler compiler)) { |
179 Uri base = new Uri(scheme: 'source', path: '/'); | 174 Uri base = new Uri(scheme: 'source', path: '/'); |
180 Uri mainUri = base.resolve('main.dart'); | 175 Uri mainUri = base.resolve('main.dart'); |
181 String mainCode = sources['main.dart']; | 176 String mainCode = sources['main.dart']; |
182 Expect.isNotNull(mainCode, 'No source code found for "main.dart"'); | 177 Expect.isNotNull(mainCode, 'No source code found for "main.dart"'); |
183 MockCompiler compiler = compilerFor(mainCode, mainUri); | 178 MockCompiler compiler = compilerFor(mainCode, mainUri); |
184 sources.forEach((String path, String code) { | 179 sources.forEach((String path, String code) { |
185 if (path == 'main.dart') return; | 180 if (path == 'main.dart') return; |
186 compiler.registerSource(base.resolve(path), code); | 181 compiler.registerSource(base.resolve(path), code); |
187 }); | 182 }); |
188 | 183 |
189 return compiler.run(mainUri).then((_) { | 184 return compiler.run(mainUri).then((_) { |
190 return check(compiler); | 185 return check(compiler); |
191 }); | 186 }); |
192 } | 187 } |
193 | 188 |
194 lego.Element findElement(compiler, String name, [Uri library]) { | 189 lego.Element findElement(compiler, String name, [Uri library]) { |
195 lego.LibraryElement lib = compiler.mainApp; | 190 lego.LibraryElement lib = compiler.mainApp; |
196 if (library != null) { | 191 if (library != null) { |
197 lib = compiler.libraryLoader.lookupLibrary(library); | 192 lib = compiler.libraryLoader.lookupLibrary(library); |
198 Expect.isNotNull(lib, 'Could not locate library $library.'); | 193 Expect.isNotNull(lib, 'Could not locate library $library.'); |
199 } | 194 } |
200 var element = lib.find(name); | 195 var element = lib.find(name); |
201 Expect.isNotNull(element, 'Could not locate $name.'); | 196 Expect.isNotNull(element, 'Could not locate $name.'); |
202 return element; | 197 return element; |
203 } | 198 } |
204 | 199 |
205 types.TypeMask findTypeMask(compiler, String name, | 200 types.TypeMask findTypeMask(compiler, String name, |
206 [String how = 'nonNullExact']) { | 201 [String how = 'nonNullExact']) { |
207 var sourceName = name; | 202 var sourceName = name; |
208 var element = compiler.mainApp.find(sourceName); | 203 var element = compiler.mainApp.find(sourceName); |
209 if (element == null) { | 204 if (element == null) { |
210 element = compiler.backend.helpers.interceptorsLibrary.find(sourceName); | 205 element = compiler.backend.helpers.interceptorsLibrary.find(sourceName); |
211 } | 206 } |
212 if (element == null) { | 207 if (element == null) { |
213 element = compiler.commonElements.coreLibrary.find(sourceName); | 208 element = compiler.commonElements.coreLibrary.find(sourceName); |
214 } | 209 } |
215 Expect.isNotNull(element, 'Could not locate $name'); | 210 Expect.isNotNull(element, 'Could not locate $name'); |
216 switch (how) { | 211 switch (how) { |
(...skipping 11 matching lines...) Expand all Loading... |
228 return new types.TypeMask.nonNullSubtype(element, compiler.world); | 223 return new types.TypeMask.nonNullSubtype(element, compiler.world); |
229 } | 224 } |
230 Expect.fail('Unknown TypeMask constructor $how'); | 225 Expect.fail('Unknown TypeMask constructor $how'); |
231 return null; | 226 return null; |
232 } | 227 } |
233 | 228 |
234 String anyIdentifier = "[a-zA-Z][a-zA-Z0-9]*"; | 229 String anyIdentifier = "[a-zA-Z][a-zA-Z0-9]*"; |
235 | 230 |
236 String getIntTypeCheck(String variable) { | 231 String getIntTypeCheck(String variable) { |
237 return "\\($variable ?!== ?\\($variable ?\\| ?0\\)|" | 232 return "\\($variable ?!== ?\\($variable ?\\| ?0\\)|" |
238 "\\($variable ?>>> ?0 ?!== ?$variable"; | 233 "\\($variable ?>>> ?0 ?!== ?$variable"; |
239 } | 234 } |
240 | 235 |
241 String getNumberTypeCheck(String variable) { | 236 String getNumberTypeCheck(String variable) { |
242 return """\\(typeof $variable ?!== ?"number"\\)"""; | 237 return """\\(typeof $variable ?!== ?"number"\\)"""; |
243 } | 238 } |
244 | 239 |
245 void checkNumberOfMatches(Iterator it, int nb) { | 240 void checkNumberOfMatches(Iterator it, int nb) { |
246 bool hasNext = it.moveNext(); | 241 bool hasNext = it.moveNext(); |
247 for (int i = 0; i < nb; i++) { | 242 for (int i = 0; i < nb; i++) { |
248 Expect.isTrue(hasNext, "Found less than $nb matches"); | 243 Expect.isTrue(hasNext, "Found less than $nb matches"); |
249 hasNext = it.moveNext(); | 244 hasNext = it.moveNext(); |
250 } | 245 } |
251 Expect.isFalse(hasNext, "Found more than $nb matches"); | 246 Expect.isFalse(hasNext, "Found more than $nb matches"); |
252 } | 247 } |
253 | 248 |
254 Future compileAndMatch(String code, String entry, RegExp regexp, | 249 Future compileAndMatch(String code, String entry, RegExp regexp, |
255 {bool useMock: false}) { | 250 {bool useMock: false}) { |
256 return compile(code, entry: entry, | 251 return compile(code, entry: entry, useMock: useMock, |
257 useMock: useMock, | |
258 check: (String generated) { | 252 check: (String generated) { |
259 Expect.isTrue(regexp.hasMatch(generated), | 253 Expect.isTrue( |
260 '"$generated" does not match /$regexp/'); | 254 regexp.hasMatch(generated), '"$generated" does not match /$regexp/'); |
261 }); | 255 }); |
262 } | 256 } |
263 | 257 |
264 Future compileAndDoNotMatch(String code, String entry, RegExp regexp) { | 258 Future compileAndDoNotMatch(String code, String entry, RegExp regexp) { |
265 return compile(code, entry: entry, check: (String generated) { | 259 return compile(code, entry: entry, check: (String generated) { |
266 Expect.isFalse(regexp.hasMatch(generated), | 260 Expect.isFalse( |
267 '"$generated" has a match in /$regexp/'); | 261 regexp.hasMatch(generated), '"$generated" has a match in /$regexp/'); |
268 }); | 262 }); |
269 } | 263 } |
270 | 264 |
271 int length(Link link) => link.isEmpty ? 0 : length(link.tail) + 1; | 265 int length(Link link) => link.isEmpty ? 0 : length(link.tail) + 1; |
272 | 266 |
273 // Does a compile and then a match where every 'x' is replaced by something | 267 // Does a compile and then a match where every 'x' is replaced by something |
274 // that matches any variable, and every space is optional. | 268 // that matches any variable, and every space is optional. |
275 Future compileAndMatchFuzzy(String code, String entry, String regexp) { | 269 Future compileAndMatchFuzzy(String code, String entry, String regexp) { |
276 return compileAndMatchFuzzyHelper(code, entry, regexp, true); | 270 return compileAndMatchFuzzyHelper(code, entry, regexp, true); |
277 } | 271 } |
278 | 272 |
279 Future compileAndDoNotMatchFuzzy(String code, String entry, String regexp) { | 273 Future compileAndDoNotMatchFuzzy(String code, String entry, String regexp) { |
280 return compileAndMatchFuzzyHelper(code, entry, regexp, false); | 274 return compileAndMatchFuzzyHelper(code, entry, regexp, false); |
281 } | 275 } |
282 | 276 |
283 Future compileAndMatchFuzzyHelper( | 277 Future compileAndMatchFuzzyHelper( |
284 String code, String entry, String regexp, bool shouldMatch) { | 278 String code, String entry, String regexp, bool shouldMatch) { |
285 return compile(code, entry: entry, check: (String generated) { | 279 return compile(code, entry: entry, check: (String generated) { |
286 final xRe = new RegExp('\\bx\\b'); | 280 final xRe = new RegExp('\\bx\\b'); |
287 regexp = regexp.replaceAll(xRe, '(?:$anyIdentifier)'); | 281 regexp = regexp.replaceAll(xRe, '(?:$anyIdentifier)'); |
288 final spaceRe = new RegExp('\\s+'); | 282 final spaceRe = new RegExp('\\s+'); |
289 regexp = regexp.replaceAll(spaceRe, '(?:\\s*)'); | 283 regexp = regexp.replaceAll(spaceRe, '(?:\\s*)'); |
290 if (shouldMatch) { | 284 if (shouldMatch) { |
291 Expect.isTrue(new RegExp(regexp).hasMatch(generated)); | 285 Expect.isTrue(new RegExp(regexp).hasMatch(generated)); |
292 } else { | 286 } else { |
293 Expect.isFalse(new RegExp(regexp).hasMatch(generated)); | 287 Expect.isFalse(new RegExp(regexp).hasMatch(generated)); |
294 } | 288 } |
295 }); | 289 }); |
296 } | 290 } |
OLD | NEW |