Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add initial macro expansion protocol #2021

Merged
merged 9 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
*.vcxproj.filters
/*.vcxproj.user
*.stamp
.dart_tool
.packages

# Gyp generated files
*.xcodeproj
Expand Down
19 changes: 11 additions & 8 deletions working/macros/api/builders.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,24 @@ abstract class TypeBuilder implements Builder {
void declareType(DeclarationCode typeDeclaration);
}

/// The interface for checking if a type implements another type.
abstract class TypeComparator {
/// Returns true if [leftType] is a subtype of [rightType].
bool isSubtypeOf(TypeAnnotation leftType, TypeAnnotation rightType);
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved

/// Returns true if [leftType] is an identical type to [rightType].
bool isExactly(TypeAnnotation leftType, TypeAnnotation rightType);
}

/// The api used by [Macro]s to contribute new (non-type)
/// declarations to the current library.
///
/// Can also be used to do subtype checks on types.
abstract class DeclarationBuilder implements Builder {
abstract class DeclarationBuilder implements Builder, TypeComparator {
/// Adds a new regular declaration to the surrounding library.
///
/// Note that type declarations are not supported.
Declaration declareInLibrary(DeclarationCode declaration);

/// Returns true if [leftType] is a subtype of [rightType].
bool isSubtypeOf(TypeAnnotation leftType, TypeAnnotation rightType);

/// Retruns true if [leftType] is an identical type to [rightType].
bool isExactly(TypeAnnotation leftType, TypeAnnotation rightType);
void declareInLibrary(DeclarationCode declaration);
}

/// The api used by [Macro]s to contribute new members to a class.
Expand Down
104 changes: 104 additions & 0 deletions working/macros/api/expansion_protocol.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import 'builders.dart';
import 'code.dart';
import 'introspection.dart';

/// The interface used by Dart language implementations, in order to load
/// and execute macros, as well as produce library augmentations from those
/// macro applications.
///
/// This class more clearly defines the role of a Dart language implementation
/// during macro discovery and expansion, and unifies how augmentation libraries
/// are produced.
abstract class MacroExecutor {
/// Invoked when an implementation discovers a new macro definition in a
/// library, and prepares this executor to run the macro.
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved
///
/// May be invoked more than once for the same macro, which will cause the
/// macro to be re-loaded. Previous [MacroClassIdentifier]s and
/// [MacroInstanceIdentifier]s given for this macro will be invalid after
/// that point and should be discarded.
///
/// Throws an exception if the macro fails to load.
Future<MacroClassIdentifier> loadMacro(Uri library, String name);
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved

/// Creates an instance of [macroClass] in the executor, and returns an
/// identifier for that instance.
///
/// Throws an exception if an instance is not created.
Future<MacroInstanceIdentifier> instantiateMacro(
MacroClassIdentifier macroClass, String constructor, Arguments arguments);

/// Runs the type phase for [macro] on a given [declaration].
///
/// Throws an exception if there is an error executing the macro.
Future<MacroExecutionResult> executeTypesPhase(
MacroInstanceIdentifier macro, Declaration declaration);

/// Runs the declarations phase for [macro] on a given [declaration].
///
/// Throws an exception if there is an error executing the macro.
Future<MacroExecutionResult> executeDeclarationsPhase(
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved
MacroInstanceIdentifier macro,
Declaration declaration,
TypeComparator typeComparator,
ClassIntrospector classIntrospector);

/// Runs the definitions phase for [macro] on a given [declaration].
///
/// Throws an exception if there is an error executing the macro.
Future<MacroExecutionResult> executeDefinitionsPhase(
MacroInstanceIdentifier macro,
Declaration declaration,
TypeComparator typeComparator,
ClassIntrospector classIntrospector,
TypeIntrospector typeIntrospector);

/// Combines multiple [MacroExecutionResult]s into a single library
/// augmentation file, and returns a [String] representing that file.
Future<String> buildAugmentationLibrary(
Iterable<MacroExecutionResult> macroResults);
}

/// The arguments passed to a macro constructor.
///
/// All argument instances must be of type [Code] or a built-in value type that
/// is serializable (num, bool, String, null, etc).
class Arguments {
final List<Object?> positional;

final Map<String, Object?> named;

Arguments(this.positional, this.named);
}

/// An opaque identifier for a macro class, retrieved by
/// [MacroExecutor.loadMacro].
///
/// Used to execute or reload this macro in the future.
abstract class MacroClassIdentifier {}

/// An opaque identifier for an instance of a macro class, retrieved by
/// [MacroExecutor.instantiateMacro].
///
/// Used to execute or reload this macro in the future.
abstract class MacroInstanceIdentifier {}

/// A summary of the results of running a macro in a given phase.
///
/// All modifications are expressed in terms of library augmentation
/// declarations.
abstract class MacroExecutionResult {
/// Any library imports that should be added to support the code used in
/// the augmentations.
Iterable<DeclarationCode> get imports;
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved

/// Any augmentations that should be applied as a result of executing a macro.
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved
Iterable<DeclarationCode> get agumentations;
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Each of the different macro execution phases.
enum Phase {
types, // Only new types are added in this phase
jakemac53 marked this conversation as resolved.
Show resolved Hide resolved
declarations, // New non-type declarations are added in this phase
defintions, // This phase allows augmenting existing declarations
}
4 changes: 4 additions & 0 deletions working/macros/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: macro_proposal
publish_to: none
environment:
sdk: ">=2.12.0 <3.0.0"