Skip to content

Commit

Permalink
Use package:_macro_host in _cfe_macros. (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmorgan authored Aug 9, 2024
1 parent db556ad commit 731c449
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 113 deletions.
19 changes: 10 additions & 9 deletions pkgs/_analyzer_macros/lib/macro_implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import 'package:macros/macros.dart';
import 'package:macros/src/executor.dart' as injected;

/// Injected macro implementation for the analyzer.
class MacroImplementation implements injected.MacroImplementation {
class AnalyzerMacroImplementation implements injected.MacroImplementation {
final Uri packageConfig;
final Map<String, String> macroImplByName;
final MacroHost _host;

MacroImplementation._(this.packageConfig, this.macroImplByName, this._host);
AnalyzerMacroImplementation._(
this.packageConfig, this.macroImplByName, this._host);

/// Starts the macro host.
///
Expand All @@ -27,11 +28,11 @@ class MacroImplementation implements injected.MacroImplementation {
/// [macroImplByName] identifies macros, it's a placeholder until we identify
/// macros using package config. Keys are macro annotation qualified names
/// (`uri#name`) and values are macro implementation qualified names.
static Future<MacroImplementation> start({
static Future<AnalyzerMacroImplementation> start({
required Uri packageConfig,
required Map<String, String> macroImplByName,
}) async =>
MacroImplementation._(
AnalyzerMacroImplementation._(
packageConfig,
macroImplByName,
await MacroHost.serve(
Expand All @@ -54,7 +55,7 @@ class AnalyzerQueryService implements QueryService {
}

class AnalyzerMacroPackageConfigs implements injected.MacroPackageConfigs {
final MacroImplementation _impl;
final AnalyzerMacroImplementation _impl;

AnalyzerMacroPackageConfigs(this._impl);

Expand All @@ -64,7 +65,7 @@ class AnalyzerMacroPackageConfigs implements injected.MacroPackageConfigs {
}

class AnalyzerMacroRunner implements injected.MacroRunner {
final MacroImplementation _impl;
final AnalyzerMacroImplementation _impl;

AnalyzerMacroRunner(this._impl);

Expand All @@ -77,7 +78,7 @@ class AnalyzerMacroRunner implements injected.MacroRunner {
}

class AnalyzerRunningMacro implements injected.RunningMacro {
final MacroImplementation _impl;
final AnalyzerMacroImplementation _impl;
final QualifiedName name;
final QualifiedName implementation;
late final Future _started;
Expand All @@ -86,8 +87,8 @@ class AnalyzerRunningMacro implements injected.RunningMacro {

// TODO(davidmorgan): should this be async, removing the need for `_started`?
// If so the API injected into analyzer+CFE needs to change to be async.
static AnalyzerRunningMacro run(MacroImplementation impl, QualifiedName name,
QualifiedName implementation) {
static AnalyzerRunningMacro run(AnalyzerMacroImplementation impl,
QualifiedName name, QualifiedName implementation) {
final result = AnalyzerRunningMacro._(impl, name, implementation);
// TODO(davidmorgan): this is currently what starts the macro running,
// make it explicit.
Expand Down
2 changes: 1 addition & 1 deletion pkgs/_analyzer_macros/test/analyzer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void main() {
final contextCollection =
AnalysisContextCollection(includedPaths: [directory.path]);
analysisContext = contextCollection.contexts.first;
injected.macroImplementation = await MacroImplementation.start(
injected.macroImplementation = await AnalyzerMacroImplementation.start(
packageConfig: Isolate.packageConfigSync!,
macroImplByName: {
'package:_test_macros/declare_x_macro.dart#DeclareX':
Expand Down
175 changes: 175 additions & 0 deletions pkgs/_cfe_macros/lib/macro_implementation.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Copyright (c) 2024, 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:_macro_host/macro_host.dart';
import 'package:dart_model/dart_model.dart';
// ignore: implementation_imports
import 'package:front_end/src/macros/macro_injected_impl.dart' as injected;
import 'package:macro_service/macro_service.dart';
import 'package:macros/macros.dart';
// ignore: implementation_imports
import 'package:macros/src/executor.dart' as injected;

/// Injected macro implementation for the analyzer.
class CfeMacroImplementation implements injected.MacroImplementation {
final Uri packageConfig;
final Map<String, String> macroImplByName;
final MacroHost _host;

CfeMacroImplementation._(
this.packageConfig, this.macroImplByName, this._host);

/// Starts the macro host.
///
/// [packageConfig] is the package config of the workspace of the code being
/// edited.
///
/// [macroImplByName] identifies macros, it's a placeholder until we identify
/// macros using package config. Keys are macro annotation qualified names
/// (`uri#name`) and values are macro implementation qualified names.
static Future<CfeMacroImplementation> start({
required Uri packageConfig,
required Map<String, String> macroImplByName,
}) async =>
CfeMacroImplementation._(
packageConfig,
macroImplByName,
await MacroHost.serve(
macroImplByName: macroImplByName,
queryService: CfeQueryService()));

@override
injected.MacroPackageConfigs get packageConfigs =>
CfeMacroPackageConfigs(this);

@override
injected.MacroRunner get macroRunner => CfeMacroRunner(this);
}

class CfeQueryService implements QueryService {
@override
Future<QueryResponse> handle(QueryRequest request) async {
return QueryResponse();
}
}

class CfeMacroPackageConfigs implements injected.MacroPackageConfigs {
final CfeMacroImplementation _impl;

CfeMacroPackageConfigs(this._impl);

@override
bool isMacro(Uri uri, String name) =>
_impl._host.isMacro(_impl.packageConfig, QualifiedName('$uri#$name'));
}

class CfeMacroRunner implements injected.MacroRunner {
final CfeMacroImplementation _impl;

CfeMacroRunner(this._impl);

@override
injected.RunningMacro run(Uri uri, String name) => CfeRunningMacro.run(
_impl,
QualifiedName('$uri#$name'),
// Look up from the macro name to its implementation.
QualifiedName(_impl.macroImplByName['$uri#$name']!));
}

class CfeRunningMacro implements injected.RunningMacro {
final CfeMacroImplementation _impl;
final QualifiedName name;
final QualifiedName implementation;
late final Future _started;

CfeRunningMacro._(this._impl, this.name, this.implementation);

// TODO(davidmorgan): should this be async, removing the need for `_started`?
// If so the API injected into analyzer+CFE needs to change to be async.
static CfeRunningMacro run(CfeMacroImplementation impl, QualifiedName name,
QualifiedName implementation) {
final result = CfeRunningMacro._(impl, name, implementation);
// TODO(davidmorgan): this is currently what starts the macro running,
// make it explicit.
result._started =
impl._host.queryMacroPhases(impl.packageConfig, implementation);
return result;
}

@override
Future<CfeMacroExecutionResult> executeDeclarationsPhase(MacroTarget target,
DeclarationPhaseIntrospector declarationsPhaseIntrospector) async {
await _started;
return CfeMacroExecutionResult(
target, await _impl._host.augment(name, AugmentRequest(phase: 2)));
}

@override
Future<CfeMacroExecutionResult> executeDefinitionsPhase(MacroTarget target,
DefinitionPhaseIntrospector definitionPhaseIntrospector) async {
await _started;
return CfeMacroExecutionResult(
target, await _impl._host.augment(name, AugmentRequest(phase: 3)));
}

@override
Future<CfeMacroExecutionResult> executeTypesPhase(
MacroTarget target, TypePhaseIntrospector typePhaseIntrospector) async {
await _started;
return CfeMacroExecutionResult(
target, await _impl._host.augment(name, AugmentRequest(phase: 1)));
}
}

/// Converts [AugmentResponse] to [injected.MacroExecutionResult].
///
/// TODO(davidmorgan): add to `AugmentationResponse` to cover all the
/// functionality of `MacroExecutionResult`.
class CfeMacroExecutionResult implements injected.MacroExecutionResult {
final MacroTarget target;
final AugmentResponse augmentResponse;

CfeMacroExecutionResult(this.target, this.augmentResponse);

@override
List<Diagnostic> get diagnostics => [];

@override
Map<Identifier, Iterable<DeclarationCode>> get enumValueAugmentations => {};

@override
MacroException? get exception => null;

@override
Map<Identifier, NamedTypeAnnotationCode> get extendsTypeAugmentations => {};

@override
Map<Identifier, Iterable<TypeAnnotationCode>> get interfaceAugmentations =>
{};

@override
Iterable<DeclarationCode> get libraryAugmentations => {};

@override
Map<Identifier, Iterable<TypeAnnotationCode>> get mixinAugmentations => {};

@override
Iterable<String> get newTypeNames => [];

@override
void serialize(Object serializer) => throw UnimplementedError();

@override
Map<Identifier, Iterable<DeclarationCode>> get typeAugmentations => {
// TODO(davidmorgan): this assumes augmentations are for the macro
// application target. Instead, it should be explicit in
// `AugmentResponse`.
// TODO(davidmorgan): empty augmentations response breaks the test,
// it's not clear why.
if (augmentResponse.augmentations.isNotEmpty)
(target as Declaration).identifier: augmentResponse.augmentations
.map((a) => DeclarationCode.fromParts([a.code]))
.toList(),
};
}
9 changes: 7 additions & 2 deletions pkgs/_cfe_macros/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ resolution: workspace
environment:
sdk: ^3.6.0-114.0.dev

dependencies:
_macro_host: any
dart_model: any
front_end: any
macro_service: any
macros: any

dev_dependencies:
dart_flutter_team_lints: ^3.0.0
front_end: any
frontend_server: any
macros: ^0.1.2-main.4
test: ^1.25.0
Loading

0 comments on commit 731c449

Please sign in to comment.