-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Closed as not planned
Closed as not planned
Copy link
Labels
area-languageDart language related items (some items might be better tracked at github.com/dart-lang/language).Dart language related items (some items might be better tracked at github.com/dart-lang/language).feature-macrosImplementation of the macros featureImplementation of the macros featurepkg-macrosThe experimental package:_macros libraryThe experimental package:_macros librarytype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)Incorrect behavior (everything from a crash to more subtle misbehavior)
Description
For the code
final variantRegex = RegExp(r'^(\w+)\((.*?)\)$');
macro class Enum
implements ClassTypesMacro, ClassDeclarationsMacro, ClassDefinitionMacro {
final String? variant1, variant2;
const Enum([this.variant1, this.variant2]);
List<String> get variants => [
if(variant1 != null) variant1!,
if(variant2 != null) variant2!
];
@override
FutureOr<void> buildTypesForClass(ClassDeclaration clazz, ClassTypeBuilder builder) {
final className = clazz.identifier.name;
for(final variant in variants) {
final match = variantRegex.firstMatch(variant);
if (match == null) {
throw Exception("Variant `$variant` is not valid");
}
final newTypeName = match.group(1)!;
final fieldTypes = match.group(2)!.split(',').map((s) => s.trim()).toList();
int count = 1;
final fields = StringBuffer();
final constructors = StringBuffer();
for(final fieldType in fieldTypes) {
fields.write("\t$fieldType v$count;\n");
constructors.write("this.v$count,");
}
builder.declareType(newTypeName, DeclarationCode.fromString('''
final class $className\$$newTypeName implements $className {
$fields
$className\$$newTypeName._($constructors);
}'''));
}
}
@override
Future<void> buildDeclarationsForClass(
ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
final className = clazz.identifier.name;
for(final variant in variants) {
final match = variantRegex.firstMatch(variant);
if (match == null) {
throw Exception("Variant `$variant` is not valid");
}
final newTypeName = match.group(1)!;
final fieldTypes = match.group(2)!.split(',').map((s) => s.trim()).toList();
int count = 1;
final constructor = StringBuffer();
for(final fieldType in fieldTypes) {
constructor.write("$fieldType v$count,");
}
builder.declareInType(DeclarationCode.fromString("factory $className.$newTypeName($constructor);"));
}
}
@override
Future<void> buildDefinitionForClass(
ClassDeclaration clazz, TypeDefinitionBuilder builder) async {
final className = clazz.identifier.name;
final constructors = await builder.constructorsOf(clazz);
for (final constructor in constructors) {
final constructorName = constructor.identifier.name;
final constructorBuilder = await builder.buildConstructor(constructor.identifier);
constructorBuilder.augment(body: FunctionBodyCode.fromString("= $className\$$constructorName._;"));
}
}
}Used like
@Enum("Variant(int)")
sealed class W {
}
void main() {
final w = W.Variant(1);
}Gives the following error
org-dartlang-augmentation:/workspaces/algebraic_types/bin/algebraic_types.dart-1:3:18: Error: A 'sealed' class can't be marked 'abstract' because it's already implicitly abstract.
Try removing the 'abstract' keyword.
augment abstract sealed class W {
^^^^^^
org-dartlang-augmentation:/workspaces/algebraic_types/bin/algebraic_types.dart-1:4:27: Error: Expected a function body or '=>'.
Try adding {}.
factory W.Variant(int v1,);
^
org-dartlang-augmentation:/workspaces/algebraic_types/bin/algebraic_types.dart-2:5:18: Error: A 'sealed' class can't be marked 'abstract' because it's already implicitly abstract.
Try removing the 'abstract' keyword.
augment abstract sealed class W {
^^^^^^
org-dartlang-augmentation:/workspaces/algebraic_types/bin/algebraic_types.dart-2:6:19: Error: Constructor 'W.Variant' conflicts with an existing constructor of the same name in the augmented class.
Try changing the name of the constructor or adding an 'augment' modifier.
augment factory W.Variant(prefix0.int v1, ) = W$Variant._;
^
org-dartlang-augmentation:/workspaces/algebraic_types/bin/algebraic_types.dart-1:4:9: Context: This is the existing constructor.
factory W.Variant(int v1,);Dart info
#### General info
- Dart 3.7.0-232.0.dev (dev) (None) on "linux_x64"
- on linux / Linux 6.6.63 #1-NixOS SMP PREEMPT_DYNAMIC Fri Nov 22 14:38:37 UTC 2024
- locale is en_US.UTF-8
#### Project info
- sdk constraint: '3.7.0-232.0.dev'
- dependencies: json
- dev_dependencies: lints, testMetadata
Metadata
Assignees
Labels
area-languageDart language related items (some items might be better tracked at github.com/dart-lang/language).Dart language related items (some items might be better tracked at github.com/dart-lang/language).feature-macrosImplementation of the macros featureImplementation of the macros featurepkg-macrosThe experimental package:_macros libraryThe experimental package:_macros librarytype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)Incorrect behavior (everything from a crash to more subtle misbehavior)
Type
Projects
Status
Done