Skip to content
This repository was archived by the owner on Apr 8, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/code_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ abstract class _AbstractCodeBuilder<A extends AstNode> extends CodeBuilder<A> {
/// **NOTE**: This currently (as of 0.2.0) has no effect. It is planned that
/// the [FileBuilder] will be able to act as a scope 'resolver' and subtly
/// rewrite the AST tree to use prefixing if required (or requested).
abstract class RequiresImport<A extends AstNode> implements CodeBuilder<A> {
/// Imports that are required for this AST to work.
List<String> get requiredImports;
abstract class ScopeAware<A extends AstNode> implements CodeBuilder<A> {
@override
A toAst() => toScopedAst(const Scope.identity());

/// Creates a copy-safe [AstNode] representing the current builder state.
///
/// Uses [scope] to output an AST re-written to use appropriate prefixes.
A toScopedAst(FileBuilder scope) => throw new UnimplementedError();
A toScopedAst(Scope scope) => throw new UnimplementedError();
}

// Creates a defensive copy of an AST node.
Expand Down
4 changes: 2 additions & 2 deletions lib/src/builders/annotation_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ part of code_builder;
/// void destroyTheWorld() { ... }
///
/// To create a `@DoNotUse('Blows up')` use [AnnotationBuilder.invoke].
abstract class AnnotationBuilder implements RequiresImport<Annotation> {
abstract class AnnotationBuilder implements ScopeAware<Annotation> {
/// Create a new annotated `const` [constructor] invocation.
///
/// May optionally specify an [importFrom] to auto-prefix the annotation _if_
Expand Down Expand Up @@ -46,7 +46,7 @@ abstract class AnnotationBuilder implements RequiresImport<Annotation> {
[String importFrom]) = _ReferenceAnnotationBuilder;
}

class _ConstructorAnnotationBuilder extends RequiresImport<Annotation>
class _ConstructorAnnotationBuilder extends ScopeAware<Annotation>
implements AnnotationBuilder {
final String _constructor;
final ExpressionBuilder _expression;
Expand Down
37 changes: 33 additions & 4 deletions lib/src/builders/file_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ abstract class FileBuilder extends _AbstractCodeBuilder<CompilationUnit> {
class LibraryBuilder extends FileBuilder {
static final Token _library = new KeywordToken(Keyword.LIBRARY, 0);

final Scope _scope;

/// Create a new standalone Dart library, optionally with a [name].
factory LibraryBuilder([String name]) {
var astNode = _emptyCompilationUnit();
Expand All @@ -39,22 +41,49 @@ class LibraryBuilder extends FileBuilder {
new LibraryIdentifier([_stringId(name)]),
null,));
}
return new LibraryBuilder._(astNode);
return new LibraryBuilder._(astNode, new Scope.dedupe());
}

/// Create a new standalone Dart library, optionally with a [name].
///
/// As references are added in the library that implements [RequiresImport]
/// As references are added in the library that implements [ScopeAware]
/// they are re-written to avoid collisions and the imports are automatically
/// included at the top with optional prefixes.
factory LibraryBuilder.autoScope({String name}) => new LibraryBuilder(name);
factory LibraryBuilder.scope({String name, Scope scope}) {
var astNode = _emptyCompilationUnit();
if (name != null) {
astNode.directives.add(new LibraryDirective(
null,
null,
_library,
new LibraryIdentifier([_stringId(name)]),
null,));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you run dartfmt on this file?

}
return new LibraryBuilder._(astNode, scope ?? new Scope());
}

LibraryBuilder._(CompilationUnit astNode) : super._(astNode);
LibraryBuilder._(CompilationUnit astNode, this._scope) : super._(astNode);

@override
void addDeclaration(CodeBuilder<Declaration> declaration) {
if (declaration is ScopeAware<Declaration>) {
_astNode.declarations.add(declaration.toScopedAst(_scope));
} else {
super.addDeclaration(declaration);
}
}

/// Adds [directive]'s resulting AST to the source.
void addDirective(CodeBuilder<Directive> directive) {
_astNode.directives.add(directive.toAst());
}

@override
CompilationUnit toAst() {
var originalAst = super.toAst();
originalAst.directives..addAll(_scope.getImports().map((i) => i.toAst()));
return originalAst;
}
}

/// Builds a `part of` [CompilationUnit] AST for an existing Dart library.
Expand Down
25 changes: 17 additions & 8 deletions lib/src/builders/method_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ part of code_builder;
/// the top level and within other methods) via [toFunctionAst].
///
/// To return nothing (`void`), use [MethodBuilder.returnVoid].
class MethodBuilder implements CodeBuilder<Declaration> {
class MethodBuilder implements
CodeBuilder<Declaration>,
ScopeAware<Declaration> {
static Token _abstract = new KeywordToken(Keyword.ABSTRACT, 0);
static Token _semicolon = new Token(TokenType.SEMICOLON, 0);
static Token _static = new KeywordToken(Keyword.STATIC, 0);
Expand Down Expand Up @@ -41,6 +43,9 @@ class MethodBuilder implements CodeBuilder<Declaration> {

MethodBuilder._(this._name, this._returnType);

@override
List<String> get requiredImports => null;

/// Lazily adds [annotation].
///
/// When the method is emitted as an AST, [AnnotationBuilder.toAst] is used.
Expand Down Expand Up @@ -76,14 +81,14 @@ class MethodBuilder implements CodeBuilder<Declaration> {
/// [toMethodAst].
@override
@visibleForTesting
Declaration toAst() => toFunctionAst();
Declaration toAst() => toScopedAst(const Scope.identity());

/// Returns a copy-safe [FunctionDeclaration] AST representing current state.
FunctionDeclaration toFunctionAst() {
FunctionDeclaration toFunctionAst({Scope scope: const Scope.identity()}) {
var functionAst = _emptyFunction()
..metadata.addAll(_annotations.map/*<Annotation>*/((a) => a.toAst()))
..name = _stringId(_name)
..returnType = _returnType?.toAst();
..returnType = _returnType?.toScopedAst(scope);
if (_returnExpression != null) {
functionAst.functionExpression = _returnExpression.toFunctionExpression();
} else {
Expand All @@ -95,7 +100,7 @@ class MethodBuilder implements CodeBuilder<Declaration> {
}
if (_parameters.isNotEmpty) {
functionAst.functionExpression.parameters.parameters
.addAll(_parameters.map/*<FormalParameter>*/((p) => p.toAst()));
.addAll(_parameters.map/*<FormalParameter>*/((p) => p.toScopedAst(scope)));
}
return functionAst;
}
Expand All @@ -104,11 +109,12 @@ class MethodBuilder implements CodeBuilder<Declaration> {
MethodDeclaration toMethodAst({
bool static: false,
bool canBeAbstract: false,
Scope scope: const Scope.identity(),
}) {
var methodAst = _emptyMethod()
..metadata.addAll(_annotations.map/*<Annotation>*/((a) => a.toAst()))
..name = _stringId(_name)
..returnType = _returnType?.toAst();
..returnType = _returnType?.toScopedAst(scope);
FunctionBody methodBody = _returnExpression?.toFunctionBody();
if (static) {
methodAst.modifierKeyword = _static;
Expand All @@ -123,12 +129,15 @@ class MethodBuilder implements CodeBuilder<Declaration> {
}
if (_parameters.isNotEmpty) {
methodAst.parameters.parameters
.addAll(_parameters.map/*<FormalParameter>*/((p) => p.toAst()));
.addAll(_parameters.map/*<FormalParameter>*/((p) => p.toScopedAst(scope)));
}
methodAst.body = methodBody;
return methodAst;
}

@override
Declaration toScopedAst(Scope scope) => toFunctionAst(scope: scope);

@override
String toString() => 'MethodBuilder ${toAst().toSource()}';

Expand Down Expand Up @@ -156,7 +165,7 @@ class MethodBuilder implements CodeBuilder<Declaration> {
_blockBody(),
),
);

// TODO: implement requiredImports
static MethodDeclaration _emptyMethod() => new MethodDeclaration(
null,
null,
Expand Down
Loading