| // 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. |
| |
| part of dart._macros; |
| |
| /// The base interface used to add declarations to the program as well |
| /// as augment existing ones. |
| /// |
| /// Can also be used to emit diagnostic messages back to the parent tool. |
| abstract interface class Builder { |
| /// Attaches [diagnostic] to the result of this macro application phase. |
| /// |
| /// Note that this will not immediately send the result, these will all be |
| /// collected and reported at once when the macro completes this phase. |
| void report(Diagnostic diagnostic); |
| } |
| |
| /// The interface for all introspection that is allowed during the type phase |
| /// (and later). |
| abstract interface class TypePhaseIntrospector { |
| /// Returns an [Identifier] for a top level [name] in [library]. |
| /// |
| /// You should only do this for libraries that are definitely in the |
| /// transitive import graph of the library you are generating code into. If |
| /// [library] is not in this transitive import graph, then an unspecified |
| /// [Exception] should be thrown. The best way to ensure this, is to have the |
| /// macro library itself import [library] (even if it doesn't directly use |
| /// it). |
| /// |
| /// When the name alone is not sufficient to disambiguate between multiple |
| /// declarations, such as the case of a field (which has a synthetic getter), |
| /// an [Identifier] pointing to the non-synthetic declaration will be |
| /// returned. Future calls to `declarationOf(identifier)` will return that |
| /// non-synthetic declaration. |
| /// |
| /// If [name] does not exist in [library], then an unspecified [Exception] |
| /// should be thrown. |
| @Deprecated( |
| 'This API should eventually be replaced with a different, safer API.') |
| Future<Identifier> resolveIdentifier(Uri library, String name); |
| } |
| |
| /// The API used by [Macro]s to contribute new type declarations to the |
| /// current library, and get [TypeAnnotation]s from runtime [Type] objects. |
| abstract interface class TypeBuilder implements Builder, TypePhaseIntrospector { |
| /// Adds a new type declaration to the surrounding library. |
| /// |
| /// The [name] must match the name of the new [typeDeclaration] (this does |
| /// not include any type parameters, just the name). |
| void declareType(String name, DeclarationCode typeDeclaration); |
| } |
| |
| /// The API used by macros in the type phase to add interfaces to an existing |
| /// type. |
| abstract interface class InterfaceTypesBuilder implements TypeBuilder { |
| /// Appends [interfaces] to the list of interfaces for this type. |
| void appendInterfaces(Iterable<TypeAnnotationCode> interfaces); |
| } |
| |
| /// The API used by macros in the type phase to add mixins to an existing |
| /// type. |
| abstract interface class MixinTypesBuilder implements TypeBuilder { |
| /// Appends [mixins] to the list of mixins for this type. |
| void appendMixins(Iterable<TypeAnnotationCode> mixins); |
| } |
| |
| /// The API used by macros in the type phase to augment classes. |
| abstract interface class ClassTypeBuilder |
| implements TypeBuilder, InterfaceTypesBuilder, MixinTypesBuilder {} |
| |
| /// The API used by macros in the type phase to augment enums. |
| abstract interface class EnumTypeBuilder |
| implements TypeBuilder, InterfaceTypesBuilder, MixinTypesBuilder {} |
| |
| /// The API used by macros in the type phase to augment mixins. |
| /// |
| /// Note that mixins don't support mixins, only interfaces. |
| abstract interface class MixinTypeBuilder |
| implements TypeBuilder, InterfaceTypesBuilder {} |
| |
| /// The interface for all introspection that is allowed during the declaration |
| /// phase (and later). |
| abstract interface class DeclarationPhaseIntrospector |
| implements TypePhaseIntrospector { |
| /// Instantiates a new [StaticType] for a given [type] annotation. |
| /// |
| /// Throws if [type] is a [RawTypeAnnotationCode], more specific subtypes must |
| /// be used, as raw [Identifier]s are not allowed. |
| /// |
| /// Throws an error if the [type] object contains [Identifier]s which cannot |
| /// be resolved. This should only happen in the case of incomplete or invalid |
| /// programs, but macros may be asked to run in this state during the |
| /// development cycle. It may be helpful for users if macros provide a best |
| /// effort implementation in that case or handle the error in a useful way. |
| Future<StaticType> resolve(TypeAnnotationCode type); |
| |
| /// The values available for [enuum]. |
| /// |
| /// This may be incomplete if additional declaration macros are going to run |
| /// on [enuum]. |
| Future<List<EnumValueDeclaration>> valuesOf(covariant EnumDeclaration enuum); |
| |
| /// The fields available for [type]. |
| /// |
| /// This may be incomplete if additional declaration macros are going to run |
| /// on [type]. |
| Future<List<FieldDeclaration>> fieldsOf(covariant TypeDeclaration type); |
| |
| /// The methods available for [type]. |
| /// |
| /// This may be incomplete if additional declaration macros are going to run |
| /// on [type]. |
| Future<List<MethodDeclaration>> methodsOf(covariant TypeDeclaration type); |
| |
| /// The constructors available for [type]. |
| /// |
| /// This may be incomplete if additional declaration macros are going to run |
| /// on [type]. |
| Future<List<ConstructorDeclaration>> constructorsOf( |
| covariant TypeDeclaration type); |
| |
| /// [TypeDeclaration]s for all the types declared in [library]. |
| /// |
| /// Note that this includes [ExtensionDeclaration]s as well, even though they |
| /// do not actually introduce a new type. |
| Future<List<TypeDeclaration>> typesOf(covariant Library library); |
| |
| /// Resolves an [identifier] to its [TypeDeclaration]. |
| /// |
| /// If [identifier] does not resolve to a [TypeDeclaration], then a |
| /// [MacroImplementationException] is thrown. |
| Future<TypeDeclaration> typeDeclarationOf(covariant Identifier identifier); |
| } |
| |
| /// 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 interface class DeclarationBuilder |
| implements Builder, DeclarationPhaseIntrospector { |
| /// Adds a new regular declaration to the surrounding library. |
| /// |
| /// Note that type declarations are not supported. |
| void declareInLibrary(DeclarationCode declaration); |
| } |
| |
| /// The API used by [Macro]s to contribute new members to a type. |
| abstract interface class MemberDeclarationBuilder |
| implements DeclarationBuilder { |
| /// Adds a new declaration to the surrounding class. |
| void declareInType(DeclarationCode declaration); |
| } |
| |
| /// The API used by [Macro]s to contribute new members or values to an enum. |
| abstract interface class EnumDeclarationBuilder |
| implements MemberDeclarationBuilder { |
| /// Adds a new enum entry declaration to the surrounding enum. |
| void declareEnumValue(DeclarationCode declaration); |
| } |
| |
| /// The interface for all introspection that is allowed during the definition |
| /// phase (and later). |
| abstract interface class DefinitionPhaseIntrospector |
| implements DeclarationPhaseIntrospector { |
| /// Resolves any [identifier] to its [Declaration]. |
| Future<Declaration> declarationOf(covariant Identifier identifier); |
| |
| /// Resolves an [identifier] referring to a type to its [TypeDeclaration]. |
| @override |
| Future<TypeDeclaration> typeDeclarationOf(covariant Identifier identifier); |
| |
| /// Infers a real type annotation for [omittedType]. |
| /// |
| /// If no type could be inferred, then a type annotation representing the |
| /// dynamic type will be given. |
| Future<TypeAnnotation> inferType(covariant OmittedTypeAnnotation omittedType); |
| |
| /// Returns a list of all the [Declaration]s in the given [library]. |
| Future<List<Declaration>> topLevelDeclarationsOf(covariant Library library); |
| } |
| |
| /// The base class for builders in the definition phase. These can convert |
| /// any [TypeAnnotation] into its corresponding [TypeDeclaration], and also |
| /// reflect more deeply on those. |
| abstract interface class DefinitionBuilder |
| implements Builder, DefinitionPhaseIntrospector {} |
| |
| /// The APIs used by [Macro]s that run on library directives, to fill in the |
| /// definitions of any declarations within that library. |
| abstract interface class LibraryDefinitionBuilder implements DefinitionBuilder { |
| /// Retrieve a [TypeDefinitionBuilder] for a type declaration with |
| /// [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// a type declaration in this library. |
| Future<TypeDefinitionBuilder> buildType(Identifier identifier); |
| |
| /// Retrieve a [FunctionDefinitionBuilder] for a function declaration with |
| /// [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// a top level function declaration in this library. |
| Future<FunctionDefinitionBuilder> buildFunction(Identifier identifier); |
| |
| /// Retrieve a [VariableDefinitionBuilder] for a variable declaration with |
| /// [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// a top level variable declaration in this library. |
| Future<VariableDefinitionBuilder> buildVariable(Identifier identifier); |
| } |
| |
| /// The APIs used by [Macro]s that run on type declarations, to fill in the |
| /// definitions of any declarations within that class. |
| abstract interface class TypeDefinitionBuilder implements DefinitionBuilder { |
| /// Retrieve a [VariableDefinitionBuilder] for a field with [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// a field in this class. |
| Future<VariableDefinitionBuilder> buildField(Identifier identifier); |
| |
| /// Retrieve a [FunctionDefinitionBuilder] for a method with [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// a method in this class. |
| Future<FunctionDefinitionBuilder> buildMethod(Identifier identifier); |
| |
| /// Retrieve a [ConstructorDefinitionBuilder] for a constructor with |
| /// [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// a constructor in this class. |
| Future<ConstructorDefinitionBuilder> buildConstructor(Identifier identifier); |
| } |
| |
| /// The APIs used by [Macro]s that run on enums, to fill in the |
| /// definitions of any declarations within that enum. |
| abstract interface class EnumDefinitionBuilder |
| implements TypeDefinitionBuilder { |
| /// Retrieve an [EnumValueDefinitionBuilder] for an entry with [identifier]. |
| /// |
| /// Throws a [MacroImplementationException] if [identifier] does not refer to |
| /// an entry on this enum. |
| Future<EnumValueDefinitionBuilder> buildEnumValue(Identifier identifier); |
| } |
| |
| /// The APIs used by [Macro]s to define the body of a constructor |
| /// or wrap the body of an existing constructor with additional statements. |
| abstract interface class ConstructorDefinitionBuilder |
| implements DefinitionBuilder { |
| /// Augments an existing constructor body with [body] and [initializers]. |
| /// |
| /// The [initializers] should not contain trailing or preceding commas. |
| /// |
| /// If [docComments] are supplied, they will be added above this augment |
| /// declaration. |
| /// |
| /// TODO: Link the library augmentations proposal to describe the semantics. |
| void augment({ |
| FunctionBodyCode? body, |
| List<Code>? initializers, |
| CommentCode? docComments, |
| }); |
| } |
| |
| /// The APIs used by [Macro]s to augment functions or methods. |
| abstract interface class FunctionDefinitionBuilder |
| implements DefinitionBuilder { |
| /// Augments the function. |
| /// |
| /// If [docComments] are supplied, they will be added above this augment |
| /// declaration. |
| /// |
| /// TODO: Link the library augmentations proposal to describe the semantics. |
| void augment( |
| FunctionBodyCode body, { |
| CommentCode? docComments, |
| }); |
| } |
| |
| /// The API used by [Macro]s to augment a top level variable or instance field. |
| abstract interface class VariableDefinitionBuilder |
| implements DefinitionBuilder { |
| /// Augments the field. |
| /// |
| /// For [getter] and [setter] the full function declaration should be |
| /// provided, minus the `augment` keyword (which will be implicitly added). |
| /// |
| /// If [initializerDocComments] are supplied, they will be added above the |
| /// augment declaration for [initializer]. It is an error to provide |
| /// [initializerDocComments] but not [initializer]. |
| /// |
| /// To provide doc comments for [getter] or [setter], just include them in |
| /// the [DeclarationCode] object for those. |
| /// |
| /// TODO: Link the library augmentations proposal to describe the semantics. |
| void augment({ |
| DeclarationCode? getter, |
| DeclarationCode? setter, |
| ExpressionCode? initializer, |
| CommentCode? initializerDocComments, |
| }); |
| } |
| |
| /// The API used by [Macro]s to augment an enum entry. |
| abstract interface class EnumValueDefinitionBuilder |
| implements DefinitionBuilder { |
| /// Augments the entry by replacing it with a new one. |
| /// |
| /// The name of the produced [entry] must match the original name. |
| void augment(DeclarationCode entry); |
| } |