Skip to content
This repository has been archived by the owner on Feb 4, 2025. It is now read-only.

Commit

Permalink
Make AugmentResponse more like MacroExecutionResult (#106)
Browse files Browse the repository at this point in the history
In preparation for adding builder types, and making `AugmentResponse` not visible in the macro APIs any more.

Will do that after #104 is also merged, as we really need both.
  • Loading branch information
jakemac53 authored Oct 21, 2024
1 parent 54e85a3 commit 18c0ffb
Show file tree
Hide file tree
Showing 12 changed files with 298 additions and 83 deletions.
30 changes: 27 additions & 3 deletions pkgs/_analyzer_macros/lib/macro_implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,34 @@ class AnalyzerMacroExecutionResult
static Future<AnalyzerMacroExecutionResult> dartModelToInjected(
macros_api_v1.MacroTarget target, AugmentResponse augmentResponse) async {
final declarations = <macros_api_v1.DeclarationCode>[];
for (final augmentation in augmentResponse.augmentations) {
declarations.add(macros_api_v1.DeclarationCode.fromParts(
await _resolveNames(augmentation.code)));
if (augmentResponse.typeAugmentations?.isNotEmpty == true) {
// TODO: Handle multiple type augmentations, or augmentations where the
// target is itself a member of a type and not the type.
final entry = augmentResponse.typeAugmentations!.entries.single;
if (entry.key != target.qualifiedName.name) {
throw UnimplementedError(
'Type augmentations are only implemented when the type is the '
'target of the augmentation.');
}
for (final augmentation in entry.value) {
declarations.add(macros_api_v1.DeclarationCode.fromParts(
await _resolveNames(augmentation.code)));
}
}

if (augmentResponse.enumValueAugmentations?.isNotEmpty == true) {
throw UnimplementedError('Enum value augmentations are not implemented');
}
if (augmentResponse.extendsTypeAugmentations?.isNotEmpty == true ||
augmentResponse.interfaceAugmentations?.isNotEmpty == true ||
augmentResponse.mixinAugmentations?.isNotEmpty == true) {
throw UnimplementedError('Type augmentations are not implemented');
}
if (augmentResponse.libraryAugmentations?.isNotEmpty == true ||
augmentResponse.newTypeNames?.isNotEmpty == true) {
throw UnimplementedError('Library augmentations are not implemented');
}

return AnalyzerMacroExecutionResult(target, declarations);
}

Expand Down
30 changes: 27 additions & 3 deletions pkgs/_cfe_macros/lib/macro_implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,34 @@ class CfeMacroExecutionResult implements macros_api_v1.MacroExecutionResult {
static Future<CfeMacroExecutionResult> dartModelToInjected(
macros_api_v1.MacroTarget target, AugmentResponse augmentResponse) async {
final declarations = <macros_api_v1.DeclarationCode>[];
for (final augmentation in augmentResponse.augmentations) {
declarations.add(macros_api_v1.DeclarationCode.fromParts(
await _resolveNames(augmentation.code)));
if (augmentResponse.typeAugmentations?.isNotEmpty == true) {
// TODO: Handle multiple type augmentations, or augmentations where the
// target is itself a member of a type and not the type.
final entry = augmentResponse.typeAugmentations!.entries.single;
if (entry.key != target.qualifiedName.name) {
throw UnimplementedError(
'Type augmentations are only implemented when the type is the '
'target of the augmentation.');
}
for (final augmentation in entry.value) {
declarations.add(macros_api_v1.DeclarationCode.fromParts(
await _resolveNames(augmentation.code)));
}
}

if (augmentResponse.enumValueAugmentations?.isNotEmpty == true) {
throw UnimplementedError('Enum value augmentations are not implemented');
}
if (augmentResponse.extendsTypeAugmentations?.isNotEmpty == true ||
augmentResponse.interfaceAugmentations?.isNotEmpty == true ||
augmentResponse.mixinAugmentations?.isNotEmpty == true) {
throw UnimplementedError('Type augmentations are not implemented');
}
if (augmentResponse.libraryAugmentations?.isNotEmpty == true ||
augmentResponse.newTypeNames?.isNotEmpty == true) {
throw UnimplementedError('Library augmentations are not implemented');
}

return CfeMacroExecutionResult(target, declarations);
}

Expand Down
2 changes: 1 addition & 1 deletion pkgs/_macro_client/lib/macro_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class MacroClient {
'Unexpected phase ${augmentRequest.phase}, '
'expected 1, 2, or 3.')
} ??
AugmentResponse(augmentations: []),
AugmentResponse(),
requestId: hostRequest.id)));
}
default:
Expand Down
108 changes: 66 additions & 42 deletions pkgs/_macro_client/test/macro_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,22 @@ void main() {
'requestId': requestId,
'type': 'AugmentResponse',
'value': {
'augmentations': [
{
'code': [
{
'type': 'String',
'value': 'int get x => 3;',
}
]
}
]
'enumValueAugmentations': <String, Object?>{},
'extendsTypeAugmentations': <String, Object?>{},
'interfaceAugmentations': <String, Object?>{},
'mixinAugmentations': <String, Object?>{},
'typeAugmentations': {
'A': [
{
'code': [
{
'type': 'String',
'value': 'int get x => 3;',
},
],
},
],
},
},
});
});
Expand Down Expand Up @@ -232,16 +238,22 @@ void main() {
'requestId': requestId,
'type': 'AugmentResponse',
'value': {
'augmentations': [
{
'code': [
{
'type': 'String',
'value': '// {"uris":{"${target.uri}":{"scopes":{}}}}'
}
]
}
]
'enumValueAugmentations': <String, Object?>{},
'extendsTypeAugmentations': <String, Object?>{},
'interfaceAugmentations': <String, Object?>{},
'mixinAugmentations': <String, Object?>{},
'typeAugmentations': {
'A': [
{
'code': [
{
'type': 'String',
'value': '// {"uris":{"${target.uri}":{"scopes":{}}}}'
}
]
}
]
}
},
},
);
Expand Down Expand Up @@ -307,17 +319,23 @@ void main() {
'requestId': requestId1,
'type': 'AugmentResponse',
'value': {
'augmentations': [
{
'code': [
{
'type': 'String',
'value':
'// {"uris":{"package:foo/foo1.dart":{"scopes":{}}}}'
}
]
}
]
'enumValueAugmentations': <String, Object?>{},
'extendsTypeAugmentations': <String, Object?>{},
'interfaceAugmentations': <String, Object?>{},
'mixinAugmentations': <String, Object?>{},
'typeAugmentations': {
'A': [
{
'code': [
{
'type': 'String',
'value':
'// {"uris":{"package:foo/foo1.dart":{"scopes":{}}}}',
},
],
},
],
},
},
},
);
Expand All @@ -328,17 +346,23 @@ void main() {
'requestId': requestId2,
'type': 'AugmentResponse',
'value': {
'augmentations': [
{
'code': [
{
'type': 'String',
'value':
'// {"uris":{"package:foo/foo2.dart":{"scopes":{}}}}'
}
]
}
]
'enumValueAugmentations': <String, Object?>{},
'extendsTypeAugmentations': <String, Object?>{},
'interfaceAugmentations': <String, Object?>{},
'mixinAugmentations': <String, Object?>{},
'typeAugmentations': {
'A': [
{
'code': [
{
'type': 'String',
'value':
'// {"uris":{"package:foo/foo2.dart":{"scopes":{}}}}',
},
],
},
],
},
},
},
);
Expand Down
22 changes: 12 additions & 10 deletions pkgs/_macro_host/test/macro_host_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ void main() {
phase: 2,
target: QualifiedName(
name: 'Foo', uri: 'package:foo/foo.dart'))),
Scope.macro.run(() => AugmentResponse(augmentations: [
Augmentation(code: [Code.string('int get x => 3;')])
])));
Scope.macro.run(() => AugmentResponse()
..typeAugmentations!['Foo'] = [
Augmentation(code: [Code.string('int get x => 3;')])
]));
});

test('hosts a macro, responds to queries', () async {
Expand All @@ -67,13 +68,14 @@ void main() {
phase: 3,
target: QualifiedName(
uri: 'package:foo/foo.dart', name: 'Foo'))),
Scope.macro.run(() => AugmentResponse(augmentations: [
Augmentation(code: [
Code.string(
'// {"uris":{"package:foo/foo.dart":{"scopes":{"Foo":{'
'"members":{},"properties":{"isClass":true}}}}}}')
])
])));
Scope.macro.run(() => AugmentResponse()
..typeAugmentations!['Foo'] = [
Augmentation(code: [
Code.string(
'// {"uris":{"package:foo/foo.dart":{"scopes":{"Foo":{'
'"members":{},"properties":{"isClass":true}}}}}}')
])
]));
});

test('hosts two macros', () async {
Expand Down
8 changes: 5 additions & 3 deletions pkgs/_test_macros/lib/declare_x_macro.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ class DeclareXImplementation implements ClassDeclarationsMacro {
Host host, AugmentRequest request) async {
// TODO(davidmorgan): make the host only run in the phases requested so
// that this is not needed.
if (request.phase != 2) return AugmentResponse(augmentations: []);
if (request.phase != 2) return AugmentResponse();

// TODO(davidmorgan): still need to pass through the augment target.
return AugmentResponse(
augmentations: [Augmentation(code: expandTemplate('int get x => 3;'))]);
return AugmentResponse()
..typeAugmentations![request.target.name] = [
Augmentation(code: expandTemplate('int get x => 3;'))
];
}
}
16 changes: 9 additions & 7 deletions pkgs/_test_macros/lib/json_codable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ class JsonCodableImplementation
Future<AugmentResponse> buildDeclarationsForClass(
Host host, AugmentRequest request) async {
final target = request.target;
return AugmentResponse(augmentations: [
Augmentation(code: expandTemplate('''
return AugmentResponse()
..typeAugmentations![request.target.name] = [
Augmentation(code: expandTemplate('''
// TODO(davidmorgan): see https://github.com/dart-lang/macros/issues/80.
// external ${target.name}.fromJson($_jsonMapType json);
// external $_jsonMapType toJson();
'''))
]);
];
}

@override
Expand All @@ -49,10 +50,11 @@ class JsonCodableImplementation
// TODO(davidmorgan): put `extends` information directly in `Interface`.
final superclassName = MacroScope.current.typeSystem.supertypeOf(target);

return AugmentResponse(augmentations: [
await _generateFromJson(host, model, target, superclassName, clazz),
await _generateToJson(host, model, target, superclassName, clazz)
]);
return AugmentResponse()
..typeAugmentations![request.target.name] = [
await _generateFromJson(host, model, target, superclassName, clazz),
await _generateToJson(host, model, target, superclassName, clazz)
];
}

Future<Augmentation> _generateFromJson(
Expand Down
7 changes: 4 additions & 3 deletions pkgs/_test_macros/lib/query_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ class QueryClassImplementation implements ClassDefinitionsMacro {
final model = await host.query(Query(
target: request.target,
));
return AugmentResponse(augmentations: [
Augmentation(code: expandTemplate('// ${json.encode(model)}'))
]);
return AugmentResponse()
..typeAugmentations![request.target.name] = [
Augmentation(code: expandTemplate('// ${json.encode(model)}'))
];
}
}
46 changes: 41 additions & 5 deletions pkgs/macro_service/lib/src/macro_service.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,50 @@ extension type AugmentRequest.fromJson(Map<String, Object?> node)
extension type AugmentResponse.fromJson(Map<String, Object?> node)
implements Object {
AugmentResponse({
List<Augmentation>? augmentations,
List<Augmentation>? libraryAugmentations,
List<String>? newTypeNames,
}) : this.fromJson({
if (augmentations != null) 'augmentations': augmentations,
'enumValueAugmentations': <String, Object?>{},
'extendsTypeAugmentations': <String, Object?>{},
'interfaceAugmentations': <String, Object?>{},
if (libraryAugmentations != null)
'libraryAugmentations': libraryAugmentations,
'mixinAugmentations': <String, Object?>{},
if (newTypeNames != null) 'newTypeNames': newTypeNames,
'typeAugmentations': <String, Object?>{},
});

/// The augmentations.
List<Augmentation> get augmentations =>
(node['augmentations'] as List).cast();
/// Any augmentations to enum values that should be applied to an enum as a result of executing a macro, indexed by the name of the enum.
Map<String, List<Augmentation>>? get enumValueAugmentations =>
(node['enumValueAugmentations'] as Map?)
?.deepCast<String, List<Augmentation>>((v) => (v as List).cast());

/// Any extends clauses that should be added to types as a result of executing a macro, indexed by the name of the augmented type declaration.
Map<String, List<Augmentation>>? get extendsTypeAugmentations =>
(node['extendsTypeAugmentations'] as Map?)
?.deepCast<String, List<Augmentation>>((v) => (v as List).cast());

/// Any interfaces that should be added to types as a result of executing a macro, indexed by the name of the augmented type declaration.
Map<String, List<Augmentation>>? get interfaceAugmentations =>
(node['interfaceAugmentations'] as Map?)
?.deepCast<String, List<Augmentation>>((v) => (v as List).cast());

/// Any augmentations that should be applied to the library as a result of executing a macro.
List<Augmentation>? get libraryAugmentations =>
(node['libraryAugmentations'] as List?)?.cast();

/// Any mixins that should be added to types as a result of executing a macro, indexed by the name of the augmented type declaration.
Map<String, List<Augmentation>>? get mixinAugmentations =>
(node['mixinAugmentations'] as Map?)
?.deepCast<String, List<Augmentation>>((v) => (v as List).cast());

/// The names of any new types declared in [libraryAugmentations].
List<String>? get newTypeNames => (node['newTypeNames'] as List?)?.cast();

/// Any augmentations that should be applied to a class as a result of executing a macro, indexed by the name of the class.
Map<String, List<Augmentation>>? get typeAugmentations =>
(node['typeAugmentations'] as Map?)
?.deepCast<String, List<Augmentation>>((v) => (v as List).cast());
}

/// Request could not be handled.
Expand Down
Loading

0 comments on commit 18c0ffb

Please sign in to comment.