Skip to content

Commit

Permalink
Add support for extension types (dart-archive/code_builder#437)
Browse files Browse the repository at this point in the history
  • Loading branch information
srujzs authored Nov 20, 2023
1 parent b9d06e6 commit baa3ea1
Show file tree
Hide file tree
Showing 15 changed files with 1,013 additions and 34 deletions.
2 changes: 1 addition & 1 deletion pkgs/code_builder/.github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
sdk: [2.19.0, dev]
sdk: [3.0.0, dev]
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d
Expand Down
4 changes: 3 additions & 1 deletion pkgs/code_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 4.8.0-wip
## 4.8.0

* Add `Expression.operatorSubtract`
* Deprecate `Expression.operatorSubstract`
Expand Down Expand Up @@ -28,6 +28,8 @@
* Add `Expression.bitwiseXorAssign`
* Add `Expression.bitwiseOrAssign`
* Allow passing an `Expression` through `literal` without an exception.
* Add support for extension types.
* Update SDK version constraints to `>=3.0.0`.

## 4.7.0

Expand Down
1 change: 1 addition & 0 deletions pkgs/code_builder/lib/code_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export 'src/specs/expression.dart'
literalString,
literalTrue;
export 'src/specs/extension.dart' show Extension, ExtensionBuilder;
export 'src/specs/extension_type.dart' show ExtensionType, ExtensionTypeBuilder;
export 'src/specs/field.dart' show Field, FieldBuilder, FieldModifier;
export 'src/specs/library.dart' show Library, LibraryBuilder;
export 'src/specs/method.dart'
Expand Down
57 changes: 57 additions & 0 deletions pkgs/code_builder/lib/src/emitter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'specs/directive.dart';
import 'specs/enum.dart';
import 'specs/expression.dart';
import 'specs/extension.dart';
import 'specs/extension_type.dart';
import 'specs/field.dart';
import 'specs/library.dart';
import 'specs/method.dart';
Expand Down Expand Up @@ -336,6 +337,62 @@ class DartEmitter extends Object
return out;
}

@override
StringSink visitExtensionType(ExtensionType spec, [StringSink? output]) {
final out = output ??= StringBuffer();
spec.docs.forEach(out.writeln);
for (var a in spec.annotations) {
visitAnnotation(a, out);
}

out.write('extension type ');
if (spec.constant) out.write('const ');
out.write(spec.name);
visitTypeParameters(spec.types.map((r) => r.type), out);
if (spec.primaryConstructorName.isNotEmpty) {
out.write('.${spec.primaryConstructorName}');
}
out.write('(');
_visitRepresentationDeclaration(spec.representationDeclaration, out);
out.write(')');

if (spec.implements.isNotEmpty) {
out
..write(' implements ')
..writeAll(
spec.implements.map<StringSink>((m) => m.type.accept(this)), ',');
}

out.writeln(' {');
for (var c in spec.constructors) {
visitConstructor(c, spec.name, out);
out.writeln();
}
for (var f in spec.fields) {
visitField(f, out);
out.writeln();
}
for (var m in spec.methods) {
visitMethod(m, out);
if (_isLambdaMethod(m)) {
out.writeln(';');
}
out.writeln();
}
out.writeln('}');
return out;
}

void _visitRepresentationDeclaration(
RepresentationDeclaration spec, StringSink out) {
spec.docs.forEach(out.writeln);
for (var a in spec.annotations) {
visitAnnotation(a, out);
}
spec.declaredRepresentationType.accept(this, out);
out.write(' ${spec.name}');
}

@override
StringSink visitDirective(Directive spec, [StringSink? output]) {
output ??= StringBuffer();
Expand Down
4 changes: 2 additions & 2 deletions pkgs/code_builder/lib/src/mixins/annotations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import 'package:built_collection/built_collection.dart';
import '../specs/expression.dart';

/// A type of AST node that can have metadata [annotations].
abstract class HasAnnotations {
abstract mixin class HasAnnotations {
/// Annotations as metadata on the node.
BuiltList<Expression> get annotations;
}

/// Compliment to the [HasAnnotations] mixin for metadata [annotations].
abstract class HasAnnotationsBuilder {
abstract mixin class HasAnnotationsBuilder {
/// Annotations as metadata on the node.
abstract ListBuilder<Expression> annotations;
}
4 changes: 2 additions & 2 deletions pkgs/code_builder/lib/src/mixins/dartdoc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

import 'package:built_collection/built_collection.dart';

abstract class HasDartDocs {
abstract mixin class HasDartDocs {
/// Dart docs.
BuiltList<String> get docs;
}

abstract class HasDartDocsBuilder {
abstract mixin class HasDartDocsBuilder {
/// Dart docs.
abstract ListBuilder<String> docs;
}
4 changes: 2 additions & 2 deletions pkgs/code_builder/lib/src/mixins/generics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import 'package:built_collection/built_collection.dart';

import '../specs/reference.dart';

abstract class HasGenerics {
abstract mixin class HasGenerics {
/// Generic type parameters.
BuiltList<Reference> get types;
}

abstract class HasGenericsBuilder {
abstract mixin class HasGenericsBuilder {
/// Generic type parameters.
abstract ListBuilder<Reference> types;
}
2 changes: 1 addition & 1 deletion pkgs/code_builder/lib/src/specs/code.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ abstract class CodeVisitor<T> implements SpecVisitor<T> {
}

/// Knowledge of how to write valid Dart code from [CodeVisitor].
abstract class CodeEmitter implements CodeVisitor<StringSink> {
abstract mixin class CodeEmitter implements CodeVisitor<StringSink> {
@protected
Allocator get allocator;

Expand Down
3 changes: 2 additions & 1 deletion pkgs/code_builder/lib/src/specs/expression.dart
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ abstract class ExpressionVisitor<T> implements SpecVisitor<T> {
/// Knowledge of how to write valid Dart code from [ExpressionVisitor].
///
/// **INTERNAL ONLY**.
abstract class ExpressionEmitter implements ExpressionVisitor<StringSink> {
abstract mixin class ExpressionEmitter
implements ExpressionVisitor<StringSink> {
@override
StringSink visitToCodeExpression(ToCodeExpression expression,
[StringSink? output]) {
Expand Down
152 changes: 152 additions & 0 deletions pkgs/code_builder/lib/src/specs/extension_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) 2023, 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:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:meta/meta.dart';

import '../base.dart';
import '../mixins/annotations.dart';
import '../mixins/dartdoc.dart';
import '../mixins/generics.dart';
import '../visitors.dart';
import 'constructor.dart';
import 'expression.dart';
import 'field.dart';
import 'method.dart';
import 'reference.dart';

part 'extension_type.g.dart';

@immutable
abstract class ExtensionType extends Object
with HasAnnotations, HasDartDocs, HasGenerics
implements Built<ExtensionType, ExtensionTypeBuilder>, Spec {
factory ExtensionType([void Function(ExtensionTypeBuilder)? updates]) =
_$ExtensionType;

ExtensionType._();

@override
BuiltList<Expression> get annotations;

@override
BuiltList<String> get docs;

/// Whether this extension type is declared as `const`.
bool get constant;

String get name;

@override
BuiltList<Reference> get types;

/// Name of the extension type's primary constructor. An empty string
/// will make it unnamed.
String get primaryConstructorName;

RepresentationDeclaration get representationDeclaration;

BuiltList<Reference> get implements;

BuiltList<Constructor> get constructors;

BuiltList<Field> get fields;

BuiltList<Method> get methods;

@override
R accept<R>(
SpecVisitor<R> visitor, [
R? context,
]) =>
visitor.visitExtensionType(this, context);
}

abstract class ExtensionTypeBuilder extends Object
with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
implements Builder<ExtensionType, ExtensionTypeBuilder> {
factory ExtensionTypeBuilder() = _$ExtensionTypeBuilder;

ExtensionTypeBuilder._();

@override
void update(void Function(ExtensionTypeBuilder)? updates) {
updates?.call(this);
}

@override
ListBuilder<Expression> annotations = ListBuilder<Expression>();

@override
ListBuilder<String> docs = ListBuilder<String>();

/// Whether this extension type is declared as `const`.
bool constant = false;

String? name;

@override
ListBuilder<Reference> types = ListBuilder<Reference>();

/// Name of the extension type's primary constructor. An empty string
/// will make it unnamed.
String primaryConstructorName = '';

RepresentationDeclaration? representationDeclaration;

ListBuilder<Reference> implements = ListBuilder<Reference>();

ListBuilder<Constructor> constructors = ListBuilder<Constructor>();

ListBuilder<Field> fields = ListBuilder<Field>();

ListBuilder<Method> methods = ListBuilder<Method>();
}

abstract class RepresentationDeclaration extends Object
with HasAnnotations, HasDartDocs
implements
Built<RepresentationDeclaration, RepresentationDeclarationBuilder> {
factory RepresentationDeclaration(
[void Function(RepresentationDeclarationBuilder)? updates]) =
_$RepresentationDeclaration;

RepresentationDeclaration._();

@override
BuiltList<Expression> get annotations;

@override
BuiltList<String> get docs;

Reference get declaredRepresentationType;

String get name;
}

abstract class RepresentationDeclarationBuilder extends Object
with HasAnnotationsBuilder, HasDartDocsBuilder
implements
Builder<RepresentationDeclaration, RepresentationDeclarationBuilder> {
factory RepresentationDeclarationBuilder() =
_$RepresentationDeclarationBuilder;

RepresentationDeclarationBuilder._();

@override
void update(void Function(RepresentationDeclarationBuilder)? updates) {
updates?.call(this);
}

@override
ListBuilder<Expression> annotations = ListBuilder<Expression>();

@override
ListBuilder<String> docs = ListBuilder<String>();

Reference? declaredRepresentationType;

String? name;
}
Loading

0 comments on commit baa3ea1

Please sign in to comment.