057d0baaf9
Change-Id: Ia8776c8aea845a7dde089d5ac9f3dab82e984f4f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/249721 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Devon Carew <devoncarew@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
251 lines
8.1 KiB
Dart
251 lines
8.1 KiB
Dart
// 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 Java code generation.
|
|
import 'package:analyzer_utilities/html_dom.dart' as dom;
|
|
import 'package:analyzer_utilities/tools.dart';
|
|
|
|
import 'api.dart';
|
|
import 'from_html.dart';
|
|
import 'to_html.dart';
|
|
|
|
/// Create a [GeneratedFile] that creates Java code and outputs it to [path].
|
|
/// [path] uses Posix-style path separators regardless of the OS.
|
|
GeneratedFile javaGeneratedFile(
|
|
String path, CodegenJavaVisitor Function(Api api) createVisitor) {
|
|
return GeneratedFile(path, (String pkgPath) async {
|
|
var visitor = createVisitor(readApi(pkgPath));
|
|
return visitor.collectCode(visitor.visitApi);
|
|
});
|
|
}
|
|
|
|
/// Iterate through the values in [map] in the order of increasing keys.
|
|
Iterable<String> _valuesSortedByKey(Map<String, String> map) {
|
|
var entries = map.entries.toList();
|
|
entries.sort((a, b) => a.key.compareTo(b.key));
|
|
return entries.map((e) => e.value);
|
|
}
|
|
|
|
/// Common code for all Java code generation.
|
|
class CodegenJavaVisitor extends HierarchicalApiVisitor with CodeGenerator {
|
|
/// Variable names which must be changed in order to avoid conflict with
|
|
/// reserved words in Java.
|
|
static const Map<String, String> _variableRenames = {'default': 'defaultSdk'};
|
|
|
|
/// Type references in the spec that are named something else in Java.
|
|
static const Map<String, String> _typeRenames = {
|
|
'bool': 'boolean',
|
|
'double': 'double',
|
|
'int': 'int',
|
|
'AvailableSuggestionRelevanceTag': 'String',
|
|
'ExecutionContextId': 'String',
|
|
'FilePath': 'String',
|
|
'DebugContextId': 'String',
|
|
'object': 'Object',
|
|
'Override': 'OverrideMember',
|
|
};
|
|
|
|
_CodegenJavaState _state = _CodegenJavaState();
|
|
|
|
/// Visitor used to produce doc comments.
|
|
final ToHtmlVisitor toHtmlVisitor;
|
|
|
|
CodegenJavaVisitor(super.api) : toHtmlVisitor = ToHtmlVisitor(api);
|
|
|
|
/// Create a constructor, using [callback] to create its contents.
|
|
void constructor(String name, void Function() callback) {
|
|
_state.constructors[name] = collectCode(callback);
|
|
}
|
|
|
|
/// Get the name of the consumer class for responses to this request.
|
|
String consumerName(Request request) {
|
|
return camelJoin([request.method, 'consumer'], doCapitalize: true);
|
|
}
|
|
|
|
/// Return true iff the passed [TypeDecl] will represent an array in Java.
|
|
bool isArray(TypeDecl type) {
|
|
return type is TypeList && isPrimitive(type.itemType);
|
|
}
|
|
|
|
/// Return true iff the passed [TypeDecl] is a type declared in the
|
|
/// spec_input.
|
|
bool isDeclaredInSpec(TypeDecl type) {
|
|
// TypeReference resolvedType = super.resolveTypeReferenceChain(type);
|
|
// if(resolvedType is TypeObject) {
|
|
// return true;
|
|
// }
|
|
if (type is TypeReference) {
|
|
return api.types.containsKey(type.typeName) && javaType(type) != 'String';
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Return true iff the passed [TypeDecl] will represent an array in Java.
|
|
bool isList(TypeDecl type) {
|
|
return type is TypeList && !isPrimitive(type.itemType);
|
|
}
|
|
|
|
/// Return true iff the passed [TypeDecl] will represent a Map in type.
|
|
bool isMap(TypeDecl type) {
|
|
return type is TypeMap;
|
|
}
|
|
|
|
/// Return true iff the passed [TypeDecl] will be represented as Object in
|
|
/// Java.
|
|
bool isObject(TypeDecl type) {
|
|
var typeStr = javaType(type);
|
|
return typeStr == 'Object';
|
|
}
|
|
|
|
/// Return true iff the passed [TypeDecl] will represent a primitive Java
|
|
/// type.
|
|
bool isPrimitive(TypeDecl type) {
|
|
if (type is TypeReference) {
|
|
var typeStr = javaType(type);
|
|
return typeStr == 'boolean' ||
|
|
typeStr == 'double' ||
|
|
typeStr == 'int' ||
|
|
typeStr == 'long';
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Convenience method for subclasses for calling docComment.
|
|
void javadocComment(List<dom.Node> docs) {
|
|
docComment(docs);
|
|
}
|
|
|
|
/// Return a Java type for the given [TypeObjectField].
|
|
String javaFieldType(TypeObjectField field) {
|
|
return javaType(field.type, field.optional);
|
|
}
|
|
|
|
/// Return a suitable representation of [name] as the name of a Java variable.
|
|
String javaName(String name) {
|
|
return _variableRenames[name] ?? name;
|
|
}
|
|
|
|
/// Convert the given [TypeDecl] to a Java type.
|
|
String javaType(TypeDecl type, [bool optional = false]) {
|
|
if (type is TypeReference) {
|
|
var resolvedType = resolveTypeReferenceChain(type) as TypeReference;
|
|
var typeName = resolvedType.typeName;
|
|
var renameTo = _typeRenames[typeName];
|
|
if (renameTo != null) {
|
|
typeName = renameTo;
|
|
if (optional) {
|
|
if (typeName == 'boolean') {
|
|
typeName = 'Boolean';
|
|
} else if (typeName == 'double') {
|
|
typeName = 'Double';
|
|
} else if (typeName == 'int') {
|
|
typeName = 'Integer';
|
|
}
|
|
}
|
|
}
|
|
return typeName;
|
|
} else if (type is TypeList) {
|
|
if (isPrimitive(type.itemType)) {
|
|
return '${javaType(type.itemType)}[]';
|
|
} else {
|
|
return 'List<${javaType(type.itemType)}>';
|
|
}
|
|
} else if (type is TypeMap) {
|
|
return 'Map<${javaType(type.keyType)}, ${javaType(type.valueType)}>';
|
|
} else if (type is TypeUnion) {
|
|
return 'Object';
|
|
} else {
|
|
throw Exception("Can't make type buildable");
|
|
}
|
|
}
|
|
|
|
/// Execute [callback], collecting any methods that are output using
|
|
/// [privateMethod] or [publicMethod], and insert the class (with methods
|
|
/// sorted). [header] is the part of the class declaration before the
|
|
/// opening brace.
|
|
void makeClass(String header, void Function() callback) {
|
|
var oldState = _state;
|
|
try {
|
|
_state = _CodegenJavaState();
|
|
callback();
|
|
writeln('$header {');
|
|
indent(() {
|
|
// fields
|
|
var allFields = _state.publicFields.values.toList();
|
|
allFields.addAll(_state.privateFields.values.toList());
|
|
for (var field in allFields) {
|
|
writeln();
|
|
write(field);
|
|
}
|
|
|
|
// constructors
|
|
var allConstructors = _state.constructors.values.toList();
|
|
for (var constructor in allConstructors) {
|
|
writeln();
|
|
write(constructor);
|
|
}
|
|
|
|
// methods (ordered by method name)
|
|
var allMethods = _valuesSortedByKey(_state.publicMethods).toList();
|
|
allMethods.addAll(_valuesSortedByKey(_state.privateMethods));
|
|
for (var method in allMethods) {
|
|
writeln();
|
|
write(method);
|
|
}
|
|
writeln();
|
|
});
|
|
writeln('}');
|
|
} finally {
|
|
_state = oldState;
|
|
}
|
|
}
|
|
|
|
/// Create a private field, using [callback] to create its contents.
|
|
void privateField(String fieldName, void Function() callback) {
|
|
_state.privateFields[fieldName] = collectCode(callback);
|
|
}
|
|
|
|
/// Create a private method, using [callback] to create its contents.
|
|
void privateMethod(String methodName, void Function() callback) {
|
|
_state.privateMethods[methodName] = collectCode(callback);
|
|
}
|
|
|
|
/// Create a public field, using [callback] to create its contents.
|
|
void publicField(String fieldName, void Function() callback) {
|
|
_state.publicFields[fieldName] = collectCode(callback);
|
|
}
|
|
|
|
/// Create a public method, using [callback] to create its contents.
|
|
void publicMethod(String methodName, void Function() callback) {
|
|
_state.publicMethods[methodName] = collectCode(callback);
|
|
}
|
|
|
|
@override
|
|
TypeDecl resolveTypeReferenceChain(TypeDecl type) {
|
|
var typeDecl = super.resolveTypeReferenceChain(type);
|
|
if (typeDecl is TypeEnum) {
|
|
return TypeReference('String', null);
|
|
}
|
|
return type;
|
|
}
|
|
}
|
|
|
|
/// State used by [CodegenJavaVisitor].
|
|
class _CodegenJavaState {
|
|
/// Temporary storage for public methods.
|
|
Map<String, String> publicMethods = <String, String>{};
|
|
|
|
/// Temporary storage for private methods.
|
|
Map<String, String> privateMethods = <String, String>{};
|
|
|
|
/// Temporary storage for public fields.
|
|
Map<String, String> publicFields = <String, String>{};
|
|
|
|
/// Temporary storage for private fields.
|
|
Map<String, String> privateFields = <String, String>{};
|
|
|
|
/// Temporary storage for constructors.
|
|
Map<String, String> constructors = <String, String>{};
|
|
}
|