Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(898)

Unified Diff: pkg/analysis_server/tool/spec/codegen_tools.dart

Issue 1431683002: Refactor analysis server code generation to re-use logic from analyzer. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analysis_server/tool/spec/codegen_matchers.dart ('k') | pkg/analysis_server/tool/spec/from_html.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analysis_server/tool/spec/codegen_tools.dart
diff --git a/pkg/analysis_server/tool/spec/codegen_tools.dart b/pkg/analysis_server/tool/spec/codegen_tools.dart
deleted file mode 100644
index f3fcb5d2524403e1c191a8151225cd04bad40d34..0000000000000000000000000000000000000000
--- a/pkg/analysis_server/tool/spec/codegen_tools.dart
+++ /dev/null
@@ -1,557 +0,0 @@
-// Copyright (c) 2014, 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.
-
-/**
- * Tools for code generation.
- */
-library codegen.tools;
-
-import 'dart:io';
-
-import 'package:html/dom.dart' as dom;
-import 'package:path/path.dart';
-
-import 'html_tools.dart';
-import 'text_formatter.dart';
-
-final RegExp trailingWhitespaceRegExp = new RegExp(r'[\n ]+$');
-final RegExp trailingSpacesInLineRegExp = new RegExp(r' +$', multiLine: true);
-
-/**
- * Join the given strings using camelCase. If [doCapitalize] is true, the first
- * part will be capitalized as well.
- */
-String camelJoin(List<String> parts, {bool doCapitalize: false}) {
- List<String> upcasedParts = <String>[];
- for (int i = 0; i < parts.length; i++) {
- if (i == 0 && !doCapitalize) {
- upcasedParts.add(parts[i]);
- } else {
- upcasedParts.add(capitalize(parts[i]));
- }
- }
- return upcasedParts.join();
-}
-
-/**
- * Capitalize and return the passed String.
- */
-String capitalize(String string) {
- return string[0].toUpperCase() + string.substring(1);
-}
-
-/**
- * Type of functions used to compute the contents of a set of generated files.
- */
-typedef Map<String, FileContentsComputer> DirectoryContentsComputer();
-
-/**
- * Type of functions used to compute the contents of a generated file.
- */
-typedef String FileContentsComputer();
-
-/**
- * Mixin class for generating code.
- */
-class CodeGenerator {
- _CodeGeneratorState _state;
-
- /**
- * Settings that specialize code generation behavior for a given
- * programming language.
- */
- CodeGeneratorSettings codeGeneratorSettings = new CodeGeneratorSettings();
-
- /**
- * Measure the width of the current indentation level.
- */
- int get indentWidth => _state.nextIndent.length;
-
- /**
- * Execute [callback], collecting any code that is output using [write]
- * or [writeln], and return the result as a string.
- */
- String collectCode(void callback(), {bool removeTrailingNewLine: false}) {
- _CodeGeneratorState oldState = _state;
- try {
- _state = new _CodeGeneratorState();
- callback();
- var text =
- _state.buffer.toString().replaceAll(trailingSpacesInLineRegExp, '');
- if (!removeTrailingNewLine) {
- return text;
- } else {
- return text.replaceAll(trailingWhitespaceRegExp, '');
- }
- } finally {
- _state = oldState;
- }
- }
-
- /**
- * Generate a doc comment based on the HTML in [docs].
- *
- * When generating java code, the output is compatible with Javadoc, which
- * understands certain HTML constructs.
- */
- void docComment(List<dom.Node> docs, {bool removeTrailingNewLine: false}) {
- if (containsOnlyWhitespace(docs)) return;
- writeln(codeGeneratorSettings.docCommentStartMarker);
- int width = codeGeneratorSettings.commentLineLength;
- bool javadocStyle = codeGeneratorSettings.languageName == 'java';
- indentBy(codeGeneratorSettings.docCommentLineLeader, () {
- write(nodesToText(docs, width - _state.indent.length, javadocStyle,
- removeTrailingNewLine: removeTrailingNewLine));
- });
- writeln(codeGeneratorSettings.docCommentEndMarker);
- }
-
- /**
- * Execute [callback], indenting any code it outputs.
- */
- void indent(void callback()) {
- indentSpecial(
- codeGeneratorSettings.indent, codeGeneratorSettings.indent, callback);
- }
-
- /**
- * Execute [callback], using [additionalIndent] to indent any code it outputs.
- */
- void indentBy(String additionalIndent, void callback()) =>
- indentSpecial(additionalIndent, additionalIndent, callback);
-
- /**
- * Execute [callback], using [additionalIndent] to indent any code it outputs.
- * The first line of output is indented by [firstAdditionalIndent] instead of
- * [additionalIndent].
- */
- void indentSpecial(
- String firstAdditionalIndent, String additionalIndent, void callback()) {
- String oldNextIndent = _state.nextIndent;
- String oldIndent = _state.indent;
- try {
- _state.nextIndent += firstAdditionalIndent;
- _state.indent += additionalIndent;
- callback();
- } finally {
- _state.nextIndent = oldNextIndent;
- _state.indent = oldIndent;
- }
- }
-
- void lineComment(List<dom.Node> docs) {
- if (containsOnlyWhitespace(docs)) {
- return;
- }
- write(codeGeneratorSettings.lineCommentLineLeader);
- int width = codeGeneratorSettings.commentLineLength;
- indentBy(codeGeneratorSettings.lineCommentLineLeader, () {
- write(nodesToText(docs, width - _state.indent.length, false));
- });
- }
-
- void outputHeader({bool javaStyle: false}) {
- String header;
- if (codeGeneratorSettings.languageName == 'java') {
- header = '''
-/*
- * Copyright (c) 2014, the Dart project authors.
- *
- * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- *
- * This file has been automatically generated. Please do not edit it manually.
- * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
- */''';
- } else if (codeGeneratorSettings.languageName == 'python') {
- header = '''
-# Copyright (c) 2014, 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 has been automatically generated. Please do not edit it manually.
-# To regenerate the file, use the script
-# "pkg/analysis_server/tool/spec/generate_files".
-''';
- } else {
- header = '''
-// Copyright (c) 2014, 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 has been automatically generated. Please do not edit it manually.
-// To regenerate the file, use the script
-// "pkg/analysis_server/tool/spec/generate_files".
-''';
- }
- writeln(header.trim());
- }
-
- /**
- * Output text without ending the current line.
- */
- void write(Object obj) {
- _state.write(obj.toString());
- }
-
- /**
- * Output text, ending the current line.
- */
- void writeln([Object obj = '']) {
- _state.write('$obj\n');
- }
-}
-
-/**
- * Controls several settings of [CodeGenerator].
- *
- * The default settings are valid for generating Java and Dart code.
- */
-class CodeGeneratorSettings {
- /**
- * Name of the language being generated. Lowercase.
- */
- String languageName;
-
- /**
- * Marker used in line comments.
- */
- String lineCommentLineLeader;
-
- /**
- * Start marker for doc comments.
- */
- String docCommentStartMarker;
-
- /**
- * Line leader for body lines in doc comments.
- */
- String docCommentLineLeader;
-
- /**
- * End marker for doc comments.
- */
- String docCommentEndMarker;
-
- /**
- * Line length for doc comment lines.
- */
- int commentLineLength;
-
- /**
- * String used for indenting code.
- */
- String indent;
-
- CodeGeneratorSettings(
- {this.languageName: 'java',
- this.lineCommentLineLeader: '// ',
- this.docCommentStartMarker: '/**',
- this.docCommentLineLeader: ' * ',
- this.docCommentEndMarker: ' */',
- this.commentLineLength: 99,
- this.indent: ' '});
-}
-
-abstract class GeneratedContent {
- FileSystemEntity get outputFile;
- bool check();
- void generate();
-}
-
-/**
- * Class representing a single output directory (either generated code or
- * generated HTML). No other content should exist in the directory.
- */
-class GeneratedDirectory extends GeneratedContent {
- /**
- * The path to the directory that will have the generated content.
- */
- final String outputDirPath;
-
- /**
- * Callback function that computes the directory contents.
- */
- final DirectoryContentsComputer directoryContentsComputer;
-
- GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer);
-
- /**
- * Get a Directory object representing the output directory.
- */
- Directory get outputFile =>
- new Directory(joinAll(posix.split(outputDirPath)));
-
- /**
- * Check whether the directory has the correct contents, and return true if it
- * does.
- */
- @override
- bool check() {
- Map<String, FileContentsComputer> map = directoryContentsComputer();
- try {
- for (String file in map.keys) {
- FileContentsComputer fileContentsComputer = map[file];
- String expectedContents = fileContentsComputer();
- File outputFile =
- new File(joinAll(posix.split(posix.join(outputDirPath, file))));
- String actualContents = outputFile.readAsStringSync();
- // Normalize Windows line endings to Unix line endings so that the
- // comparison doesn't fail on Windows.
- actualContents = actualContents.replaceAll('\r\n', '\n');
- if (expectedContents != actualContents) {
- return false;
- }
- }
- int nonHiddenFileCount = 0;
- outputFile
- .listSync(recursive: false, followLinks: false)
- .forEach((FileSystemEntity fileSystemEntity) {
- if (fileSystemEntity is File &&
- !basename(fileSystemEntity.path).startsWith('.')) {
- nonHiddenFileCount++;
- }
- });
- if (nonHiddenFileCount != map.length) {
- // The number of files generated doesn't match the number we expected to
- // generate.
- return false;
- }
- } catch (e) {
- // There was a problem reading the file (most likely because it didn't
- // exist). Treat that the same as if the file doesn't have the expected
- // contents.
- return false;
- }
- return true;
- }
-
- /**
- * Replace the directory with the correct contents. [spec] is the "tool/spec"
- * directory. If [spec] is unspecified, it is assumed to be the directory
- * containing Platform.executable.
- */
- @override
- void generate() {
- try {
- // delete the contents of the directory (and the directory itself)
- outputFile.deleteSync(recursive: true);
- } catch (e) {
- // Error caught while trying to delete the directory, this can happen if
- // it didn't yet exist.
- }
- // re-create the empty directory
- outputFile.createSync(recursive: true);
-
- // generate all of the files in the directory
- Map<String, FileContentsComputer> map = directoryContentsComputer();
- map.forEach((String file, FileContentsComputer fileContentsComputer) {
- File outputFile = new File(joinAll(posix.split(outputDirPath + file)));
- outputFile.writeAsStringSync(fileContentsComputer());
- });
- }
-}
-
-/**
- * Class representing a single output file (either generated code or generated
- * HTML).
- */
-class GeneratedFile extends GeneratedContent {
- /**
- * The output file to which generated output should be written, relative to
- * the "tool/spec" directory. This filename uses the posix path separator
- * ('/') regardless of the OS.
- */
- final String outputPath;
-
- /**
- * Callback function which computes the file.
- */
- final FileContentsComputer computeContents;
-
- GeneratedFile(this.outputPath, this.computeContents);
-
- /**
- * Get a File object representing the output file.
- */
- File get outputFile => new File(joinAll(posix.split(outputPath)));
-
- /**
- * Check whether the file has the correct contents, and return true if it
- * does.
- */
- @override
- bool check() {
- String expectedContents = computeContents();
- try {
- String actualContents = outputFile.readAsStringSync();
- // Normalize Windows line endings to Unix line endings so that the
- // comparison doesn't fail on Windows.
- actualContents = actualContents.replaceAll('\r\n', '\n');
- return expectedContents == actualContents;
- } catch (e) {
- // There was a problem reading the file (most likely because it didn't
- // exist). Treat that the same as if the file doesn't have the expected
- // contents.
- return false;
- }
- }
-
- /**
- * Replace the file with the correct contents. [spec] is the "tool/spec"
- * directory. If [spec] is unspecified, it is assumed to be the directory
- * containing Platform.executable.
- */
- void generate() {
- outputFile.writeAsStringSync(computeContents());
- }
-}
-
-/**
- * Mixin class for generating HTML representations of code that are suitable
- * for enclosing inside a <pre> element.
- */
-abstract class HtmlCodeGenerator {
- _HtmlCodeGeneratorState _state;
-
- /**
- * Add the given [node] to the HTML output.
- */
- void add(dom.Node node) {
- _state.add(node);
- }
-
- /**
- * Add the given [nodes] to the HTML output.
- */
- void addAll(Iterable<dom.Node> nodes) {
- for (dom.Node node in nodes) {
- _state.add(node);
- }
- }
-
- /**
- * Execute [callback], collecting any code that is output using [write],
- * [writeln], [add], or [addAll], and return the result as a list of DOM
- * nodes.
- */
- List<dom.Node> collectHtml(void callback()) {
- _HtmlCodeGeneratorState oldState = _state;
- try {
- _state = new _HtmlCodeGeneratorState();
- if (callback != null) {
- callback();
- }
- return _state.buffer;
- } finally {
- _state = oldState;
- }
- }
-
- /**
- * Execute [callback], wrapping its output in an element with the given
- * [name] and [attributes].
- */
- void element(String name, Map<String, String> attributes, [void callback()]) {
- add(makeElement(name, attributes, collectHtml(callback)));
- }
-
- /**
- * Execute [callback], indenting any code it outputs by two spaces.
- */
- void indent(void callback()) {
- String oldIndent = _state.indent;
- try {
- _state.indent += ' ';
- callback();
- } finally {
- _state.indent = oldIndent;
- }
- }
-
- /**
- * Output text without ending the current line.
- */
- void write(Object obj) {
- _state.write(obj.toString());
- }
-
- /**
- * Output text, ending the current line.
- */
- void writeln([Object obj = '']) {
- _state.write('$obj\n');
- }
-}
-
-/**
- * State used by [CodeGenerator].
- */
-class _CodeGeneratorState {
- StringBuffer buffer = new StringBuffer();
- String nextIndent = '';
- String indent = '';
- bool indentNeeded = true;
-
- void write(String text) {
- List<String> lines = text.split('\n');
- for (int i = 0; i < lines.length; i++) {
- if (i == lines.length - 1 && lines[i].isEmpty) {
- break;
- }
- if (indentNeeded) {
- buffer.write(nextIndent);
- nextIndent = indent;
- }
- indentNeeded = false;
- buffer.write(lines[i]);
- if (i != lines.length - 1) {
- buffer.writeln();
- indentNeeded = true;
- }
- }
- }
-}
-
-/**
- * State used by [HtmlCodeGenerator].
- */
-class _HtmlCodeGeneratorState {
- List<dom.Node> buffer = <dom.Node>[];
- String indent = '';
- bool indentNeeded = true;
-
- void add(dom.Node node) {
- if (node is dom.Text) {
- write(node.text);
- } else {
- buffer.add(node);
- }
- }
-
- void write(String text) {
- if (text.isEmpty) {
- return;
- }
- if (indentNeeded) {
- buffer.add(new dom.Text(indent));
- }
- List<String> lines = text.split('\n');
- if (lines.last.isEmpty) {
- lines.removeLast();
- buffer.add(new dom.Text(lines.join('\n$indent') + '\n'));
- indentNeeded = true;
- } else {
- buffer.add(new dom.Text(lines.join('\n$indent')));
- indentNeeded = false;
- }
- }
-}
« no previous file with comments | « pkg/analysis_server/tool/spec/codegen_matchers.dart ('k') | pkg/analysis_server/tool/spec/from_html.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698