fb2d1171e5
Modifies `GeneratedDirectory.outputDirPath` and `GeneratedFile.outputPath` to be relative to the SDK's `pkg` directory rather than relative to the containing package. Accordingly, modifies the `GeneratedContent` methods `check`, `checkAll`, `generate`, `generateAll`, `output`, as well as the `DirectoryContentsComputer` and `FileContentsComputer` callbacks, so that their first parameter is the path to the `pkg` directory rather than the path to the containing package. Also modifies the `readApi` functions in `pkg/analysis_server` and `pkg/analyzer_plugin` to accept a path to the `pkg` directory rather than a path to the containing package, since these functions are called by code generation callbacks. These changes should make code generation logic easier to reason about. They also will make it easier to move the outputs of code generation from one package to another, which will pave the way for some follow-up work in which I intend to start sharing error message representations belonging to `pkg/analyzer`, `pkg/front_end`, and `pkg/_fe_analyzer_shared`. Change-Id: Ia9b369b16f2df931c8a472f91400f2c5a0b8be9d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/438480 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
146 lines
4.7 KiB
Dart
146 lines
4.7 KiB
Dart
// Copyright (c) 2017, 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.
|
|
|
|
import 'package:analyzer_utilities/tools.dart';
|
|
|
|
import 'api.dart';
|
|
import 'codegen_dart.dart';
|
|
import 'from_html.dart';
|
|
|
|
final GeneratedFile target = GeneratedFile(
|
|
'analyzer_plugin/lib/protocol/protocol_constants.dart', (pkgRoot) async {
|
|
var visitor = _CodegenVisitor(readApi(pkgRoot));
|
|
return visitor.collectCode(visitor.visitApi);
|
|
});
|
|
|
|
/// A visitor that produces Dart code defining constants associated with the
|
|
/// API.
|
|
class _CodegenVisitor extends DartCodegenVisitor with CodeGenerator {
|
|
_CodegenVisitor(super.api) {
|
|
codeGeneratorSettings.commentLineLength = 79;
|
|
codeGeneratorSettings.docCommentStartMarker = null;
|
|
codeGeneratorSettings.docCommentLineLeader = '/// ';
|
|
codeGeneratorSettings.docCommentEndMarker = null;
|
|
codeGeneratorSettings.languageName = 'dart';
|
|
}
|
|
|
|
/// Generate the given [constant].
|
|
void generateConstant(_Constant constant) {
|
|
write('const String ');
|
|
write(constant.name);
|
|
write(' = ');
|
|
write(constant.value);
|
|
writeln(';');
|
|
}
|
|
|
|
/// Generate all of the constants associated with the [api].
|
|
void generateConstants() {
|
|
var visitor = _ConstantVisitor(api);
|
|
visitor.visitApi();
|
|
var constants = visitor.constants;
|
|
constants.sort((first, second) => first.name.compareTo(second.name));
|
|
for (var constant in constants) {
|
|
generateConstant(constant);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void visitApi() {
|
|
outputHeader(year: '2017');
|
|
writeln();
|
|
generateConstants();
|
|
}
|
|
}
|
|
|
|
/// A representation of a constant that is to be generated.
|
|
class _Constant {
|
|
/// The name of the constant.
|
|
final String name;
|
|
|
|
/// The value of the constant.
|
|
final String value;
|
|
|
|
/// Initialize a newly created constant.
|
|
_Constant(this.name, this.value);
|
|
}
|
|
|
|
/// A visitor that visits an API to compute a list of constants to be generated.
|
|
class _ConstantVisitor extends HierarchicalApiVisitor {
|
|
/// The list of constants to be generated.
|
|
List<_Constant> constants = <_Constant>[];
|
|
|
|
/// Initialize a newly created visitor to visit the given [api].
|
|
_ConstantVisitor(super.api);
|
|
|
|
@override
|
|
void visitNotification(Notification notification) {
|
|
var domainName = notification.domainName;
|
|
var event = notification.event;
|
|
|
|
var constantName = _generateName(domainName, 'notification', event);
|
|
constants.add(_Constant(constantName, "'$domainName.$event'"));
|
|
_addFieldConstants(constantName, notification.params);
|
|
}
|
|
|
|
@override
|
|
void visitRequest(Request request) {
|
|
var domainName = request.domainName;
|
|
var method = request.method;
|
|
|
|
var requestConstantName = _generateName(domainName, 'request', method);
|
|
constants.add(_Constant(requestConstantName, "'$domainName.$method'"));
|
|
_addFieldConstants(requestConstantName, request.params);
|
|
|
|
var responseConstantName = _generateName(domainName, 'response', method);
|
|
_addFieldConstants(responseConstantName, request.result);
|
|
}
|
|
|
|
/// Generate a constant for each of the fields in the given [type], where the
|
|
/// name of each constant will be composed from the [parentName] and the name
|
|
/// of the field.
|
|
void _addFieldConstants(String parentName, TypeObject? type) {
|
|
if (type == null) {
|
|
return;
|
|
}
|
|
for (var field in type.fields) {
|
|
var name = field.name;
|
|
var components = <String>[];
|
|
components.add(parentName);
|
|
components.addAll(_split(name));
|
|
var fieldConstantName = _fromComponents(components);
|
|
constants.add(_Constant(fieldConstantName, "'$name'"));
|
|
}
|
|
}
|
|
|
|
/// Return a name generated by converting each of the given [components] to an
|
|
/// uppercase equivalent, then joining them with underscores.
|
|
String _fromComponents(List<String> components) =>
|
|
components.map((String component) => component.toUpperCase()).join('_');
|
|
|
|
/// Generate a name from the [domainName], [kind] and [name] components.
|
|
String _generateName(String domainName, String kind, String name) {
|
|
var components = <String>[];
|
|
components.addAll(_split(domainName));
|
|
components.add(kind);
|
|
components.addAll(_split(name));
|
|
return _fromComponents(components);
|
|
}
|
|
|
|
/// Return the components of the given [string] that are indicated by an upper
|
|
/// case letter.
|
|
Iterable<String> _split(String first) {
|
|
var regExp = RegExp('[A-Z]');
|
|
var components = <String>[];
|
|
var start = 1;
|
|
var index = first.indexOf(regExp, start);
|
|
while (index >= 0) {
|
|
components.add(first.substring(start - 1, index));
|
|
start = index + 1;
|
|
index = first.indexOf(regExp, start);
|
|
}
|
|
components.add(first.substring(start - 1));
|
|
return components;
|
|
}
|
|
}
|