@@ -89,7 +89,7 @@ more of the macro interfaces, then the annotation is treated as an application
89
89
of the ` myCoolMacro ` macro to the class MyClass.
90
90
91
91
Macro applications can also be passed arguments, either in the form of
92
- [ Code] [ ] expressions or certain types of literal values. See
92
+ [ Code] [ ] expressions, [ Identifier ] [ ] s, or certain types of literal values. See
93
93
[ Macro Arguments] ( #Macro-arguments ) for more information on how these arguments
94
94
are handled when executing macros.
95
95
@@ -123,6 +123,37 @@ Most of the time, like here, a macro takes the arguments you pass it and
123
123
interpolates them back into code that it generates, so passing the arguments as
124
124
code is what you want.
125
125
126
+ ### Identifier arguments
127
+
128
+ If you want to be able to introspect on an identifier passed in to you, you can
129
+ do that as well, consider the following:
130
+
131
+ ``` dart
132
+ @GenerateSerializers(MyType)
133
+ library my.library;
134
+
135
+ class MyType {
136
+ final String myField;
137
+
138
+ MyType({required this.myField});
139
+ }
140
+
141
+ /// Generated by introspecting on the fields of [MyType].
142
+ class MyTypeSerializer implements Serializer<MyType> {
143
+ Map<String, Object?> serialize(MyType instance) => {
144
+ 'myField': instance.myField,
145
+ };
146
+ }
147
+
148
+ class MyTypeDeserializer implements Deserializer<MyType> {
149
+ MyType deserialize(Map<String, Object> json) =>
150
+ MyType(myField: json['myField'] as String);
151
+ }
152
+ ```
153
+
154
+ Here the macro takes an ` Identifier ` argument, and introspects on it to know
155
+ how to generate the desired serialization and deserialization classes.
156
+
126
157
### Value arguments
127
158
128
159
Sometimes, though, the macro wants to receive an actual argument value. For
@@ -466,18 +497,20 @@ This does have two interesting and possibly unexpected consequences:
466
497
Macros attach new code to the declaration the macro is applied to by calling
467
498
methods on the builder object given to the macro. For example, a
468
499
declaration-phase macro applied to a class declaration is given a
469
- [ ClassDeclarationBuilder] . That class exposes an [ ` addToClass() ` ] [ addtoclass ]
470
- method that adds the given code to the class as a new member.
500
+ [ ClassMemberDeclarationBuilder] . That class exposes a
501
+ [ ` declareInClass() ` ] [ declareInClass ] method that adds the given code to the
502
+ class as a new member.
471
503
472
- [ addtoclass ] : https://jakemac53.github.io/macro_prototype/doc/api/definition/ClassDeclarationBuilder/addToClass.html
504
+ [ ClassMemberDeclarationBuilder ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart#L93
505
+ [ declareInClass ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart#L95
473
506
474
507
The code itself is an instance of a special [ Code] [ ] class (or one of its
475
508
subclasses). This is a first-class object that represents a well-formed piece of
476
509
Dart code. We use this instead of bare strings containing Dart syntax because a
477
510
code object carries more than just the bare Dart code. In particular, it keeps
478
511
track of how identifiers in the code are resolved.
479
512
480
- [ Code ] : https://jakemac53. github.io/macro_prototype/doc/api/definition/Code-class.html
513
+ [ Code ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart#L9
481
514
482
515
Also, when code objects are creating by combining fragments of other code (for
483
516
example arguments to macros), the resulting code object may keep track of the
@@ -512,21 +545,6 @@ of a given pieces of syntax.
512
545
** TODO** : We are considering exposing more properties on Code objects to allow
513
546
introspection (#1933 ).
514
547
515
- ### Fragments
516
-
517
- Sometimes when building a piece of Dart code for a macro's output, it's
518
- convenient to work with fragments of Dart code that are not themselves valid
519
- complete pieces of Dart syntax. For example, imagine a macro that wraps a given
520
- expression in ` { return ` and ` ; } ` . Those fragments that are prepended and
521
- appended around the expression are not valid standalone productions in the Dart
522
- grammar.
523
-
524
- To represent those, we also have a [ Fragment] [ ] class. Fragments work more like
525
- unparsed strings. They can be concatenated and composed to produce a Code object
526
- when the result is valid Dart syntax.
527
-
528
- [ Fragment ] : https://jakemac53.github.io/macro_prototype/doc/api/definition/Fragment-class.html
529
-
530
548
### Identifiers and resolution
531
549
532
550
The classic problem in macro systems since they were first invented in Lisp and
@@ -657,6 +675,8 @@ that top level declaration and insert that into the generated code.
657
675
658
676
** TODO: Define this API. See [ here] ( https://github.com/dart-lang/language/pull/1779#discussion_r683843130 ) .**
659
677
678
+ [ Identifier ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart#L15
679
+
660
680
### Generating macro applications
661
681
662
682
Since macros are regular Dart code and classes, one macro can instantiate and
@@ -788,8 +808,8 @@ In a sandbox environment or isolate, create an instance of the corresponding
788
808
macro class for each macro application. Pass in any macro application arguments
789
809
to the macro's constructor. If a parameter's type is ` Code ` or a subclass,
790
810
convert the argument expression to a ` Code ` object. Any bare identifiers in the
791
- argument expression are converted to ` Identifier ` instances whose scope is the
792
- library of the macro application .
811
+ argument expression are converted to ` Identifier ` (see
812
+ [ Identifier Scope ] ( #Identifier-Scope ) for scoping information) .
793
813
794
814
Run all of the macros in phase order:
795
815
@@ -885,23 +905,35 @@ Each argument in the metadata annotation for the macro application is converted
885
905
to a form that the corresponding constructor on the macro class expects, which
886
906
it specifies through parameter types:
887
907
888
- * If the parameter type is ` bool ` , ` double ` , ` int ` , ` Null ` , ` num ` , or ` String `
889
- (or the nullable forms of any of those), then the argument expression must
890
- be a Boolean, number, null, or string literal. Number literals may be
891
- negated. String literals may not contain any interpolation, but may be
892
- adjacent strings.
908
+ * If the parameter type is ` bool ` , ` double ` , ` int ` , ` Null ` , ` num ` , ` String ` ,
909
+ ` List ` , ` Set ` , or ` Map ` , (or the nullable forms of any of those), then the
910
+ argument expression must be a boolean, number, null, string, list, set, or
911
+ map literal.
912
+
913
+ * Number literals may be negated.
914
+ * String literals may not contain any interpolation, but may be adjacent
915
+ strings, and may be raw strings.
916
+ * List, Set and Map literals may only contain entries matching any of the
917
+ supported argument types. If the parameter type specifies a generic type
918
+ argument, it must be one of the allowed parameter types or ` Object ` ,
919
+ recursively. Note that ` Object ` is allowed in order to exclude null items,
920
+ but all the actual entries must be of one of the supported types.
893
921
894
922
** TODO** : Do we want to allow more complex expressions? Could we allow
895
923
constant expressions whose identifiers can be successfully resolved before
896
924
macro expansion (#1929 )?
897
925
898
- * Else, the argument expression is automatically converted to an object of
899
- type [ Code] [ ] representing the unevaluated expression.
926
+ * If the parameter type is ` Code ` (or a subtype of ` Code ` ), the argument
927
+ expression is automatically converted to a corresponding ` Code ` instance.
928
+ These provided code expressions may contain identifiers.
900
929
901
- Note that this implicit lifting of the argument expression only happens when
902
- the macro constructor is invoked through a macro application. If a macro
903
- class is directly constructed in Dart (for example, in test code for the
904
- macro), then the caller is responsible for creating the Code object.
930
+ * If the parameter type is ` Identifier ` then a single identifier must be
931
+ passed, and it will be converted to a corresponding ` Identifier ` instance.
932
+
933
+ Note that this implicit lifting of the argument expression only happens when
934
+ the macro constructor is invoked through a macro application. If a macro
935
+ class is directly constructed in Dart (for example, in test code for the
936
+ macro), then the caller is responsible for creating the Code object.
905
937
906
938
As usual, it is a compile-time error if the type of any argument value (which
907
939
may be a Code object) is not a subtype of the corresponding parameter type.
@@ -910,6 +942,37 @@ It is a compile-time error if an macro class constructor invoked by a macro
910
942
application has a parameter whose type is not Code (or any subtype of it) or
911
943
one of the aforementioned primitive types (or a nullable type of any of those).
912
944
945
+ #### Identifier Scope
946
+
947
+ The following rules apply to any ` Identifier ` passed as an argument to a macro
948
+ application, whether as a part of a ` Code ` expression or directly as an
949
+ ` Identifier ` instance.
950
+
951
+ The scope of any ` Identifier ` argument is the same as the scope in which the
952
+ identifier appears in the source code, which is the same as the argument scope
953
+ for a metadata annotation on a declaration. This means:
954
+
955
+ * Identifiers in macro application arguments may only refer to static and top
956
+ level members.
957
+ * They cannot refer to local or instance variables, as those can never be in scope
958
+ where a macro application appears.
959
+ * Identifiers referring to static class members may be unqualified if the
960
+ annotation appears on a member of that class.
961
+ * For qualified references, only the unqualified name is visible to the macro.
962
+ When the identifier is interpolated into an augmentation library, it may be
963
+ converted back into a fully qualified reference if needed (although the
964
+ prefix may change, or a prefix may be added). This means all of the
965
+ following examples are supported, and for each you would only see ` myMember `
966
+ as the ` name ` of the identifier:
967
+ - ` @MyMacro(some_prefix.myMember) `
968
+ - ` @MyMacro(SomeClass.myMember) `
969
+ - ` @MyMacro(some_prefix.SomeClass.myMember) `
970
+
971
+ All identifiers passed to macro constructors must resolve to a real declaration
972
+ by the time macro expansion has completed. They may resolve to generated
973
+ identifiers, including ones generated by the macro they were passed to,
974
+ although that design may be inadvisable.
975
+
913
976
### Runtime environment
914
977
915
978
Since macros are executed at compile time directly inside the compiler, they run
0 commit comments