Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 /** | 5 /** |
| 6 * Tools for code generation. | 6 * Tools for code generation. |
| 7 */ | 7 */ |
| 8 library codegen.tools; | 8 library codegen.tools; |
| 9 | 9 |
| 10 import 'dart:io'; | 10 import 'dart:io'; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 } | 76 } |
| 77 | 77 |
| 78 /** | 78 /** |
| 79 * Execute [callback], indenting any code it outputs by two spaces. | 79 * Execute [callback], indenting any code it outputs by two spaces. |
| 80 */ | 80 */ |
| 81 void indent(void callback()) => indentSpecial(' ', ' ', callback); | 81 void indent(void callback()) => indentSpecial(' ', ' ', callback); |
| 82 | 82 |
| 83 /** | 83 /** |
| 84 * Execute [callback], using [additionalIndent] to indent any code it outputs. | 84 * Execute [callback], using [additionalIndent] to indent any code it outputs. |
| 85 */ | 85 */ |
| 86 void indentBy(String additionalIndent, void callback()) => indentSpecial(addit ionalIndent, additionalIndent, callback); | 86 void indentBy(String additionalIndent, void callback()) => |
| 87 indentSpecial(additionalIndent, additionalIndent, callback); | |
| 87 | 88 |
| 88 /** | 89 /** |
| 89 * Execute [callback], using [additionalIndent] to indent any code it outputs. | 90 * Execute [callback], using [additionalIndent] to indent any code it outputs. |
| 90 * The first line of output is indented by [firstAdditionalIndent] instead of | 91 * The first line of output is indented by [firstAdditionalIndent] instead of |
| 91 * [additionalIndent]. | 92 * [additionalIndent]. |
| 92 */ | 93 */ |
| 93 void indentSpecial(String firstAdditionalIndent, String additionalIndent, void callback()) { | 94 void indentSpecial(String firstAdditionalIndent, String additionalIndent, void |
| 95 callback()) { | |
| 94 String oldNextIndent = _state.nextIndent; | 96 String oldNextIndent = _state.nextIndent; |
| 95 String oldIndent = _state.indent; | 97 String oldIndent = _state.indent; |
| 96 try { | 98 try { |
| 97 _state.nextIndent += firstAdditionalIndent; | 99 _state.nextIndent += firstAdditionalIndent; |
| 98 _state.indent += additionalIndent; | 100 _state.indent += additionalIndent; |
| 99 callback(); | 101 callback(); |
| 100 } finally { | 102 } finally { |
| 101 _state.nextIndent = oldNextIndent; | 103 _state.nextIndent = oldNextIndent; |
| 102 _state.indent = oldIndent; | 104 _state.indent = oldIndent; |
| 103 } | 105 } |
| 104 } | 106 } |
| 105 | 107 |
| 106 /** | 108 /** |
| 107 * Measure the width of the current indentation level. | 109 * Measure the width of the current indentation level. |
| 108 */ | 110 */ |
| 109 int get indentWidth => _state.nextIndent.length; | 111 int get indentWidth => _state.nextIndent.length; |
| 110 | 112 |
| 111 /** | 113 /** |
| 112 * Generate a doc comment based on the HTML in [docs]. | 114 * Generate a doc comment based on the HTML in [docs]. |
| 113 * | 115 * |
| 114 * If [javadocStyle] is true, then the output is compatable with Javadoc, | 116 * If [javadocStyle] is true, then the output is compatable with Javadoc, |
| 115 * which understands certain HTML constructs. | 117 * which understands certain HTML constructs. |
| 116 */ | 118 */ |
| 117 void docComment(List<dom.Node> docs, {int width: 79, bool javadocStyle: false} ) { | 119 void docComment(List<dom.Node> docs, {int width: 79, bool javadocStyle: |
| 120 false}) { | |
| 118 writeln('/**'); | 121 writeln('/**'); |
| 119 indentBy(' * ', () { | 122 indentBy(' * ', () { |
| 120 write(nodesToText(docs, width - _state.indent.length, javadocStyle)); | 123 write(nodesToText(docs, width - _state.indent.length, javadocStyle)); |
| 121 }); | 124 }); |
| 122 writeln(' */'); | 125 writeln(' */'); |
| 123 } | 126 } |
| 124 | 127 |
| 125 void outputHeader({bool javaStyle: false}) { | 128 void outputHeader({bool javaStyle: false}) { |
| 126 String header; | 129 String header; |
| 127 if (javaStyle) { | 130 if (javaStyle) { |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 buffer.add(new dom.Text(lines.join('\n$indent') + '\n')); | 295 buffer.add(new dom.Text(lines.join('\n$indent') + '\n')); |
| 293 indentNeeded = true; | 296 indentNeeded = true; |
| 294 } else { | 297 } else { |
| 295 buffer.add(new dom.Text(lines.join('\n$indent'))); | 298 buffer.add(new dom.Text(lines.join('\n$indent'))); |
| 296 indentNeeded = false; | 299 indentNeeded = false; |
| 297 } | 300 } |
| 298 } | 301 } |
| 299 } | 302 } |
| 300 | 303 |
| 301 /** | 304 /** |
| 302 * Type of functions used to compute the contents of generated files. | 305 * Type of functions used to compute the contents of a generated file. |
| 303 */ | 306 */ |
| 304 typedef String FileContentsComputer(); | 307 typedef String FileContentsComputer(); |
| 305 | 308 |
| 309 /** | |
| 310 * Type of functions used to compute the contents of a set of generated files. | |
| 311 */ | |
| 306 typedef Map<String, FileContentsComputer> DirectoryContentsComputer(); | 312 typedef Map<String, FileContentsComputer> DirectoryContentsComputer(); |
| 307 | 313 |
| 308 abstract class GeneratedContent { | 314 abstract class GeneratedContent { |
| 309 FileSystemEntity get outputFile; | 315 FileSystemEntity get outputFile; |
| 310 bool check(); | 316 bool check(); |
| 311 void generate(); | 317 void generate(); |
| 312 } | 318 } |
| 313 | 319 |
| 314 /** | 320 /** |
| 315 * Class representing a single output file (either generated code or generated | 321 * Class representing a single output file (either generated code or generated |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 /** | 361 /** |
| 356 * Replace the file with the correct contents. [spec] is the "tool/spec" | 362 * Replace the file with the correct contents. [spec] is the "tool/spec" |
| 357 * directory. If [spec] is unspecified, it is assumed to be the directory | 363 * directory. If [spec] is unspecified, it is assumed to be the directory |
| 358 * containing Platform.executable. | 364 * containing Platform.executable. |
| 359 */ | 365 */ |
| 360 void generate() { | 366 void generate() { |
| 361 outputFile.writeAsStringSync(computeContents()); | 367 outputFile.writeAsStringSync(computeContents()); |
| 362 } | 368 } |
| 363 } | 369 } |
| 364 | 370 |
| 371 /** | |
| 372 * Class representing a single output directory (either generated code or | |
| 373 * generated HTML). No other content should exisit in the directory. | |
| 374 */ | |
| 365 class GeneratedDirectory extends GeneratedContent { | 375 class GeneratedDirectory extends GeneratedContent { |
| 366 | 376 |
| 377 /** | |
| 378 * The path to the directory that will have the generated content. | |
| 379 */ | |
| 367 final String outputDirPath; | 380 final String outputDirPath; |
| 381 | |
| 382 /** | |
| 383 * Callback function which computes the directory contents. | |
| 384 */ | |
| 368 final DirectoryContentsComputer directoryContentsComputer; | 385 final DirectoryContentsComputer directoryContentsComputer; |
| 386 | |
| 369 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); | 387 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); |
| 370 | 388 |
| 371 /** | 389 /** |
| 372 * Get a Directory object representing the output directory. | 390 * Get a Directory object representing the output directory. |
| 373 */ | 391 */ |
| 374 Directory get outputFile => new Directory(joinAll(posix.split(outputDirPath))) ; | 392 Directory get outputFile => |
| 393 new Directory(joinAll(posix.split(outputDirPath))); | |
| 375 | 394 |
| 395 /** | |
| 396 * Check whether the directory has the correct contents, and return true if it | |
| 397 * does. | |
| 398 */ | |
| 376 @override | 399 @override |
| 377 bool check() { | 400 bool check() { |
| 378 // TODO (jwren) the lists of files in the directories need to be compared to | |
| 379 // ensure no unexpected files have been added | |
| 380 Map<String, FileContentsComputer> map = directoryContentsComputer(); | 401 Map<String, FileContentsComputer> map = directoryContentsComputer(); |
| 381 map.forEach((String file, FileContentsComputer fileContentsComputer) { | 402 map.forEach((String file, FileContentsComputer fileContentsComputer) { |
| 382 String expectedContents = fileContentsComputer(); | 403 String expectedContents = fileContentsComputer(); |
| 383 File outputFile = new File(joinAll(posix.split(outputDirPath + file))); | 404 File outputFile = new File(joinAll(posix.split(outputDirPath + file))); |
|
Paul Berry
2014/08/14 12:44:05
Can we change this to:
File outputFile = new Fi
jwren
2014/08/14 18:12:29
Done.
| |
| 384 try { | 405 try { |
| 385 if (expectedContents != outputFile.readAsStringSync()) { | 406 if (expectedContents != outputFile.readAsStringSync()) { |
| 386 return false; | 407 return false; |
| 387 } | 408 } |
| 388 } catch (e) { | 409 } catch (e) { |
|
Paul Berry
2014/08/14 12:44:05
Let's move the try/catch out so that its scope inc
jwren
2014/08/14 18:12:29
Done.
| |
| 389 // There was a problem reading the file (most likely because it didn't | 410 // There was a problem reading the file (most likely because it didn't |
| 390 // exist). Treat that the same as if the file doesn't have the expected | 411 // exist). Treat that the same as if the file doesn't have the expected |
| 391 // contents. | 412 // contents. |
| 392 return false; | 413 return false; |
| 393 } | 414 } |
| 394 }); | 415 }); |
| 395 return true; | 416 return outputFile.listSync().length == map.length; |
| 396 } | 417 } |
| 397 | 418 |
| 419 /** | |
| 420 * Replace the directory with the correct contents. [spec] is the "tool/spec" | |
| 421 * directory. If [spec] is unspecified, it is assumed to be the directory | |
| 422 * containing Platform.executable. | |
| 423 */ | |
| 398 @override | 424 @override |
| 399 void generate() { | 425 void generate() { |
| 400 // TODO (jwren) Delete contents in the directory first. | 426 // delete the contents of the directory (and the directory itself) |
| 427 outputFile.deleteSync(recursive: true); | |
|
Paul Berry
2014/08/14 12:44:05
Put a try/catch around this line as well, so that
jwren
2014/08/14 18:12:29
Done.
| |
| 428 // re-create the empty directory | |
| 429 outputFile.createSync(recursive: true); | |
| 430 | |
| 431 // generate all of the files in the directory | |
| 401 Map<String, FileContentsComputer> map = directoryContentsComputer(); | 432 Map<String, FileContentsComputer> map = directoryContentsComputer(); |
| 402 map.forEach((String file, FileContentsComputer fileContentsComputer) { | 433 map.forEach((String file, FileContentsComputer fileContentsComputer) { |
| 403 File outputFile = new File(joinAll(posix.split(outputDirPath + file))); | 434 File outputFile = new File(joinAll(posix.split(outputDirPath + file))); |
| 404 outputFile.writeAsStringSync(fileContentsComputer()); | 435 outputFile.writeAsStringSync(fileContentsComputer()); |
| 405 }); | 436 }); |
| 406 } | 437 } |
| 407 } | 438 } |
| OLD | NEW |