blob: e1e12fee1a116c7a7fdf588b87eea93cc789f237 [file] [log] [blame]
// Copyright (c) 2021, 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 'dart:async';
import 'dart:isolate';
import 'dart:mirrors';
import '../executor_shared/builder_impls.dart';
import '../executor_shared/introspection_impls.dart';
import '../executor_shared/response_impls.dart';
import '../executor_shared/protocol.dart';
import '../api.dart';
/// Spawns a new isolate for loading and executing macros.
void spawn(SendPort sendPort) {
ReceivePort receivePort = new ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((message) async {
Response response;
if (message is LoadMacroRequest) {
response = await _loadMacro(message);
} else if (message is InstantiateMacroRequest) {
response = await _instantiateMacro(message);
} else if (message is ExecuteDefinitionsPhaseRequest) {
response = await _executeDefinitionsPhase(message);
} else {
throw new StateError('Unrecognized event type $message');
}
sendPort.send(response);
});
}
/// Maps macro identifiers to class mirrors.
final _macroClasses = <MacroClassIdentifierImpl, ClassMirror>{};
/// Handles [LoadMacroRequest]s.
Future<Response> _loadMacro(LoadMacroRequest request) async {
try {
MacroClassIdentifierImpl identifier =
new MacroClassIdentifierImpl(request.library, request.name);
if (_macroClasses.containsKey(identifier)) {
throw new UnsupportedError(
'Reloading macros is not supported by this implementation');
}
LibraryMirror libMirror =
await currentMirrorSystem().isolate.loadUri(request.library);
ClassMirror macroClass =
libMirror.declarations[new Symbol(request.name)] as ClassMirror;
_macroClasses[identifier] = macroClass;
return new Response(
response: identifier,
requestId: request.id,
responseType: MessageType.macroClassIdentifier);
} catch (e) {
return new Response(
error: e, requestId: request.id, responseType: MessageType.error);
}
}
/// Maps macro instance identifiers to instances.
final _macroInstances = <MacroInstanceIdentifierImpl, Macro>{};
/// Handles [InstantiateMacroRequest]s.
Future<Response> _instantiateMacro(InstantiateMacroRequest request) async {
try {
ClassMirror? clazz = _macroClasses[request.macroClass];
if (clazz == null) {
throw new ArgumentError('Unrecognized macro class ${request.macroClass}');
}
Macro instance = clazz.newInstance(
new Symbol(request.constructorName), request.arguments.positional, {
for (MapEntry<String, Object?> entry in request.arguments.named.entries)
new Symbol(entry.key): entry.value,
}).reflectee as Macro;
MacroInstanceIdentifierImpl identifier = new MacroInstanceIdentifierImpl();
_macroInstances[identifier] = instance;
return new Response(
response: identifier,
requestId: request.id,
responseType: MessageType.macroInstanceIdentifier);
} catch (e) {
return new Response(
error: e, requestId: request.id, responseType: MessageType.error);
}
}
Future<Response> _executeDefinitionsPhase(
ExecuteDefinitionsPhaseRequest request) async {
try {
Macro? instance = _macroInstances[request.macro];
if (instance == null) {
throw new StateError('Unrecognized macro instance ${request.macro}\n'
'Known instances: $_macroInstances)');
}
DeclarationImpl declaration = request.declaration;
if (instance is FunctionDefinitionMacro &&
declaration is FunctionDeclarationImpl) {
FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
declaration,
request.classIntrospector.instance as ClassIntrospector,
request.typeResolver.instance as TypeResolver,
request.typeDeclarationResolver.instance as TypeDeclarationResolver);
await instance.buildDefinitionForFunction(declaration, builder);
return new Response(
response: builder.result,
requestId: request.id,
responseType: MessageType.macroExecutionResult);
} else if (instance is MethodDefinitionMacro &&
declaration is MethodDeclarationImpl) {
FunctionDefinitionBuilderImpl builder = new FunctionDefinitionBuilderImpl(
declaration,
request.classIntrospector.instance as ClassIntrospector,
request.typeResolver.instance as TypeResolver,
request.typeDeclarationResolver.instance as TypeDeclarationResolver);
await instance.buildDefinitionForMethod(declaration, builder);
return new SerializableResponse(
responseType: MessageType.macroExecutionResult,
response: builder.result,
requestId: request.id,
serializationZoneId: request.serializationZoneId);
} else {
throw new UnsupportedError(
'Only Method and Function Definition Macros are supported currently');
}
} catch (e) {
return new Response(
error: e, requestId: request.id, responseType: MessageType.error);
}
}