Skip to content

Commit

Permalink
Add support for generic types in methods and as cast (dart-archive/…
Browse files Browse the repository at this point in the history
…code_builder#70)

* Add support for generic types and as cast

* Update CHANGELOG and pubspec.

* Rename name: to constructor:
  • Loading branch information
matanlurey authored Jan 31, 2017
1 parent ae77038 commit 2cd87a9
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 74 deletions.
65 changes: 62 additions & 3 deletions pkgs/code_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,67 @@
## 1.0.0-beta+3

- Added support for `genericTypes` parameter for `ExpressionBuilder#invoke`:

```dart
expect(
explicitThis.invoke('doThing', [literal(true)], genericTypes: [
lib$core.bool,
]),
equalsSource(r'''
this.doThing<bool>(true)
'''),
);
```

- Added a `castAs` method to `ExpressionBuilder`:

```dart
expect(
literal(1.0).castAs(lib$core.num),
equalsSource(r'''
1.0 as num
'''),
);
```

### BREAKING CHANGES

- Removed `namedNewInstance` and `namedConstInstance`, replaced with `constructor: `:

```dart
expect(
reference('Foo').newInstance([], constructor: 'other'),
equalsSource(r'''
new Foo.other()
'''),
);
```

- Renamed `named` parameter to `namedArguments`:

```dart
expect(
reference('doThing').call(
[literal(true)],
namedArguments: {
'otherFlag': literal(false),
},
),
equalsSource(r'''
doThing(true, otherFlag: false)
'''),
);
```

## 1.0.0-beta+2

- BREAKING CHANGE: `MethodModifier.async`, `MethodModifier.asyncStar` and
`MethodModifier.syncStar` are now `MethodModifier.asAsync`,
`MethodModifier.asAsyncStar` and `MethodModifier.asSyncStar`
### BREAKING CHANGES

Avoid creating symbols that can collide with the Dart language:

- `MethodModifier.async` -> `MethodModifier.asAsync`
- `MethodModifier.asyncStar` -> `MethodModifier.asAsyncStar`
- `MethodModifier.syncStar` -> `MethodModifier.asSyncStar`

## 1.0.0-beta+1

Expand Down
3 changes: 3 additions & 0 deletions pkgs/code_builder/lib/dart/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class DartCore {
/// References [dart_core.int].
final ReferenceBuilder int = _ref('int');

/// References [dart_core.num].
final ReferenceBuilder num = _ref('num');

/// References [dart_core.AbstractClassInstantiationError].
final ReferenceBuilder AbstractClassInstantiationError =
_ref('AbstractClassInstantiationError');
Expand Down
35 changes: 24 additions & 11 deletions pkgs/code_builder/lib/src/builders/expression.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ part 'expression/assert.dart';
part 'expression/assign.dart';
part 'expression/await.dart';
part 'expression/cascade.dart';
part 'expression/cast.dart';
part 'expression/index.dart';
part 'expression/invocation.dart';
part 'expression/negate.dart';
Expand Down Expand Up @@ -216,15 +217,18 @@ abstract class AbstractExpressionMixin implements ExpressionBuilder {

@override
InvocationBuilder call(
Iterable<ExpressionBuilder> positionalArguments, [
Map<String, ExpressionBuilder> namedArguments = const {},
]) {
Iterable<ExpressionBuilder> positionalArguments, {
Map<String, ExpressionBuilder> namedArguments: const {},
}) {
final invocation = new InvocationBuilder._(this);
positionalArguments.forEach(invocation.addPositionalArgument);
namedArguments.forEach(invocation.addNamedArgument);
return invocation;
}

@override
ExpressionBuilder castAs(TypeBuilder type) => new _AsCast(this, type);

@override
ExpressionBuilder cascade(
Iterable<ExpressionBuilder> create(ExpressionBuilder self),
Expand Down Expand Up @@ -261,10 +265,15 @@ abstract class AbstractExpressionMixin implements ExpressionBuilder {
@override
InvocationBuilder invoke(
String method,
Iterable<ExpressionBuilder> positionalArguments, [
Map<String, ExpressionBuilder> namedArguments = const {},
]) {
final invocation = new InvocationBuilder._on(this, method);
Iterable<ExpressionBuilder> positionalArguments, {
Iterable<TypeBuilder> genericTypes: const [],
Map<String, ExpressionBuilder> namedArguments: const {},
}) {
final invocation = new InvocationBuilder._on(
this,
method,
genericTypes.toList(),
);
positionalArguments.forEach(invocation.addPositionalArgument);
namedArguments.forEach(invocation.addNamedArgument);
return invocation;
Expand Down Expand Up @@ -381,9 +390,12 @@ abstract class ExpressionBuilder

/// Returns as an [InvocationBuilder] with arguments added.
InvocationBuilder call(
Iterable<ExpressionBuilder> positionalArguments, [
Iterable<ExpressionBuilder> positionalArguments, {
Map<String, ExpressionBuilder> namedArguments,
]);
});

/// Returns the expression casted as [type].
ExpressionBuilder castAs(TypeBuilder type);

/// Return as an [ExpressionBuilder] with `..` appended.
ExpressionBuilder cascade(
Expand All @@ -405,9 +417,10 @@ abstract class ExpressionBuilder
/// Returns as an [InvocationBuilder] on [method] of this expression.
InvocationBuilder invoke(
String method,
Iterable<ExpressionBuilder> positionalArguments, [
Iterable<ExpressionBuilder> positionalArguments, {
Iterable<TypeBuilder> genericTypes,
Map<String, ExpressionBuilder> namedArguments,
]);
});

/// Returns as an [ExpressionBuilder] negating using the `!` operator.
ExpressionBuilder negate();
Expand Down
24 changes: 24 additions & 0 deletions pkgs/code_builder/lib/src/builders/expression/cast.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2017, 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 code_builder.src.builders.expression;

class _AsCast extends TopLevelMixin with AbstractExpressionMixin {
final ExpressionBuilder _target;
final TypeBuilder _type;

_AsCast(this._target, this._type);

@override
AstNode buildAst([Scope scope]) => buildExpression(scope);

@override
Expression buildExpression([Scope scope]) {
return astFactory.asExpression(
_target.buildExpression(scope),
$as,
_type.buildType(scope),
);
}
}
30 changes: 22 additions & 8 deletions pkgs/code_builder/lib/src/builders/expression/invocation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ abstract class AbstractInvocationBuilderMixin implements InvocationBuilder {
}

/// Returns an [ArgumentList] AST.
ArgumentList buildArgumentList([Scope scope]) {
ArgumentList buildArgumentList({
Scope scope,
}) {
final allArguments = <Expression>[];
allArguments.addAll(
_positional.map/*<Expression>*/((e) => e.buildExpression(scope)));
_positional.map/*<Expression>*/((e) => e.buildExpression(scope)),
);
_named.forEach((name, e) {
allArguments.add(astFactory.namedExpression(
astFactory.label(
Expand Down Expand Up @@ -51,8 +54,12 @@ abstract class InvocationBuilder
return new _FunctionInvocationBuilder(target);
}

factory InvocationBuilder._on(ExpressionBuilder target, String method) {
return new _MethodInvocationBuilder(target, method);
factory InvocationBuilder._on(
ExpressionBuilder target,
String method,
List<TypeBuilder> generics,
) {
return new _MethodInvocationBuilder(target, method, generics);
}

/// Adds [argument] as a [name]d argument to this method call.
Expand All @@ -74,27 +81,34 @@ class _FunctionInvocationBuilder extends Object
return astFactory.functionExpressionInvocation(
_target.buildExpression(scope),
null,
buildArgumentList(scope),
buildArgumentList(scope: scope),
);
}
}

class _MethodInvocationBuilder extends Object
with AbstractInvocationBuilderMixin, AbstractExpressionMixin, TopLevelMixin
implements InvocationBuilder {
final List<TypeBuilder> _generics;
final String _method;
final ExpressionBuilder _target;

_MethodInvocationBuilder(this._target, this._method);
_MethodInvocationBuilder(this._target, this._method, this._generics);

@override
Expression buildExpression([Scope scope]) {
return astFactory.methodInvocation(
_target.buildExpression(scope),
$period,
stringIdentifier(_method),
null,
buildArgumentList(scope),
_generics.isNotEmpty
? new TypeArgumentList(
$openBracket,
_generics.map((t) => t.buildType(scope)).toList(),
$closeBracket,
)
: null,
buildArgumentList(scope: scope),
);
}
}
48 changes: 17 additions & 31 deletions pkgs/code_builder/lib/src/builders/type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,28 @@ part 'type/new_instance.dart';
abstract class AbstractTypeBuilderMixin {
/// Invokes `const` on this type.
NewInstanceBuilder constInstance(
Iterable<ExpressionBuilder> positional, [
Map<String, ExpressionBuilder> named = const {},
]) {
final builder = new NewInstanceBuilder._const(this);
_addArguments(builder, positional, named);
return builder;
}

/// Invokes `const` on this type with a [name]d constructor.
NewInstanceBuilder namedConstInstance(
String name,
Iterable<ExpressionBuilder> positional, [
Map<String, ExpressionBuilder> named = const {},
]) {
final builder = new NewInstanceBuilder._const(this, name);
_addArguments(builder, positional, named);
Iterable<ExpressionBuilder> positionalArguments, {
String constructor,
Map<String, ExpressionBuilder> namedArguments: const {},
}) {
final builder = new NewInstanceBuilder._const(
this,
constructor: constructor,
);
_addArguments(builder, positionalArguments, namedArguments);
return builder;
}

/// Invokes `new` on this type.
NewInstanceBuilder newInstance(
Iterable<ExpressionBuilder> positional, [
Map<String, ExpressionBuilder> named = const {},
]) {
final builder = new NewInstanceBuilder._new(this);
_addArguments(builder, positional, named);
return builder;
}

/// Invokes `new` on this type with a [name]d constructor.
NewInstanceBuilder namedNewInstance(
String name,
Iterable<ExpressionBuilder> positional, [
Map<String, ExpressionBuilder> named = const {},
]) {
final builder = new NewInstanceBuilder._new(this, name);
Iterable<ExpressionBuilder> positional, {
String constructor,
Map<String, ExpressionBuilder> named: const {},
}) {
final builder = new NewInstanceBuilder._new(
this,
constructor: constructor,
);
_addArguments(builder, positional, named);
return builder;
}
Expand Down
42 changes: 29 additions & 13 deletions pkgs/code_builder/lib/src/builders/type/new_instance.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,53 @@ part of code_builder.src.builders.type;
///
/// See [TypeBuilder]:
/// - [TypeBuilder.constInstance]
/// - [TypeBuilder.namedConstInstance]
/// - [TypeBuilder.newInstance]
/// - [TypeBuilder.namedNewInstance]
abstract class NewInstanceBuilder
implements AnnotationBuilder, InvocationBuilder {
factory NewInstanceBuilder._const(TypeBuilder type, [String name]) {
return new _NewInvocationBuilderImpl(Keyword.CONST, type, name);
factory NewInstanceBuilder._const(
TypeBuilder type, {
String constructor,
}) {
return new _NewInvocationBuilderImpl(
Keyword.CONST,
type,
constructor,
);
}

factory NewInstanceBuilder._new(TypeBuilder type, [String name]) {
return new _NewInvocationBuilderImpl(Keyword.NEW, type, name);
factory NewInstanceBuilder._new(
TypeBuilder type, {
String constructor,
}) {
return new _NewInvocationBuilderImpl(
Keyword.NEW,
type,
constructor,
);
}
}

class _NewInvocationBuilderImpl extends Object
with AbstractExpressionMixin, AbstractInvocationBuilderMixin, TopLevelMixin
implements NewInstanceBuilder {
final String _name;
final String _constructor;
final Keyword _keyword;
final TypeBuilder _type;

_NewInvocationBuilderImpl(this._keyword, this._type, [this._name]);
_NewInvocationBuilderImpl(
this._keyword,
this._type,
this._constructor,
);

@override
Annotation buildAnnotation([Scope scope]) {
return astFactory.annotation(
$at,
_type.buildType(scope).name,
$period,
_name != null ? stringIdentifier(_name) : null,
buildArgumentList(scope),
_constructor != null ? stringIdentifier(_constructor) : null,
buildArgumentList(scope: scope),
);
}

Expand All @@ -48,10 +64,10 @@ class _NewInvocationBuilderImpl extends Object
new KeywordToken(_keyword, 0),
astFactory.constructorName(
_type.buildType(scope),
_name != null ? $period : null,
_name != null ? stringIdentifier(_name) : null,
_constructor != null ? $period : null,
_constructor != null ? stringIdentifier(_constructor) : null,
),
buildArgumentList(scope),
buildArgumentList(scope: scope),
);
}
}
2 changes: 1 addition & 1 deletion pkgs/code_builder/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: code_builder
version: 1.0.0-beta+2
version: 1.0.0-beta+3
description: A fluent API for generating Dart code
author: Dart Team <[email protected]>
homepage: https://github.com/dart-lang/code_builder
Expand Down
Loading

0 comments on commit 2cd87a9

Please sign in to comment.