From 528393fdc200223e6924faf6730a30adbd3f06ec Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 4 Jan 2017 20:23:13 -0500 Subject: [PATCH] New features for 1.0.0-beta (dart-lang/code_builder#52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add for/for-in loop Closes https://github.com/dart-lang/code_builder/issues/49 * Add support for while/do-while * Add constructor initializers Closes https://github.com/dart-lang/code_builder/issues/50 * Update CHANGELOG and pubspec for beta * Add “name” getter for ParameterBuilder Partial support towards https://github.com/dart-lang/code_builder/issues/43 * Update CHANGELOG * Address feedback --- pkgs/code_builder/CHANGELOG.md | 9 +- pkgs/code_builder/lib/code_builder.dart | 4 +- .../lib/src/builders/expression.dart | 61 ++++++++- .../src/builders/expression/operators.dart | 43 +++++++ .../code_builder/lib/src/builders/method.dart | 78 ++++++++++- .../lib/src/builders/parameter.dart | 18 ++- .../lib/src/builders/statement.dart | 4 + .../lib/src/builders/statement/for.dart | 121 ++++++++++++++++++ .../lib/src/builders/statement/while.dart | 44 +++++++ pkgs/code_builder/lib/src/tokens.dart | 21 +++ pkgs/code_builder/pubspec.yaml | 2 +- .../test/builders/class_test.dart | 15 +++ .../test/builders/statement_test.dart | 44 +++++++ 13 files changed, 444 insertions(+), 20 deletions(-) create mode 100644 pkgs/code_builder/lib/src/builders/statement/for.dart create mode 100644 pkgs/code_builder/lib/src/builders/statement/while.dart diff --git a/pkgs/code_builder/CHANGELOG.md b/pkgs/code_builder/CHANGELOG.md index a45bafc33..be412e6e3 100644 --- a/pkgs/code_builder/CHANGELOG.md +++ b/pkgs/code_builder/CHANGELOG.md @@ -1,12 +1,13 @@ -## 1.0.0-alpha+9 +## 1.0.0-beta - Add support for `async`, `sync`, `sync*` functions - Add support for expression `asAwait`, `asYield`, `asYieldStar` - Add `toExportBuilder` and `toImportBuilder` to types and references - -## 1.0.0-alpha+8 - - Fix an import scoping bug in `return` statements and named constructor invocations. +- Added constructor initializer support +- Add `while` and `do {} while` loop support +- Add `for` and `for-in` support +- Added a `name` getter for `ParameterBuilder` ## 1.0.0-alpha+7 diff --git a/pkgs/code_builder/lib/code_builder.dart b/pkgs/code_builder/lib/code_builder.dart index ed6494ee9..26a9ae82c 100644 --- a/pkgs/code_builder/lib/code_builder.dart +++ b/pkgs/code_builder/lib/code_builder.dart @@ -36,6 +36,8 @@ export 'src/builders/statement.dart' elseIf, elseThen, returnVoid, + ForStatementBuilder, IfStatementBuilder, - StatementBuilder; + StatementBuilder, + WhileStatementBuilder; export 'src/builders/type.dart' show NewInstanceBuilder, TypeBuilder; diff --git a/pkgs/code_builder/lib/src/builders/expression.dart b/pkgs/code_builder/lib/src/builders/expression.dart index b3f957d56..4a0d4e0b2 100644 --- a/pkgs/code_builder/lib/src/builders/expression.dart +++ b/pkgs/code_builder/lib/src/builders/expression.dart @@ -14,6 +14,7 @@ import 'package:code_builder/src/builders/reference.dart'; import 'package:code_builder/src/builders/shared.dart'; import 'package:code_builder/src/builders/statement.dart'; import 'package:code_builder/src/builders/statement/if.dart'; +import 'package:code_builder/src/builders/statement/while.dart'; import 'package:code_builder/src/builders/type.dart'; import 'package:code_builder/src/tokens.dart'; @@ -35,6 +36,9 @@ final _null = astFactory.nullLiteral(new KeywordToken(Keyword.NULL, 0)); final _true = astFactory.booleanLiteral(new KeywordToken(Keyword.TRUE, 0), true); +/// A reference to `super`. +ExpressionBuilder get superRef => new _SuperExpression(); + /// Returns a pre-defined literal expression of [value]. /// /// Only primitive values are allowed. @@ -123,6 +127,24 @@ abstract class AbstractExpressionMixin implements ExpressionBuilder { ); } + @override + ExpressionBuilder operator >(ExpressionBuilder other) { + return new _AsBinaryExpression( + this, + other, + $gt, + ); + } + + @override + ExpressionBuilder operator <(ExpressionBuilder other) { + return new _AsBinaryExpression( + this, + other, + $lt, + ); + } + @override ExpressionBuilder and(ExpressionBuilder other) { return new _AsBinaryExpression( @@ -176,6 +198,11 @@ abstract class AbstractExpressionMixin implements ExpressionBuilder { @override StatementBuilder asYieldStar() => new _AsYield(this, true); + @override + WhileStatementBuilder asWhile({bool asDo: false}) { + return new WhileStatementBuilder(asDo, this); + } + @override Statement buildStatement([Scope scope]) { return asStatement().buildStatement(scope); @@ -200,6 +227,9 @@ abstract class AbstractExpressionMixin implements ExpressionBuilder { return new _CascadeExpression(this, create(reference('.'))); } + @override + ExpressionBuilder decrement() => new _DecrementExpression(this); + @override ExpressionBuilder equals(ExpressionBuilder other) { return new _AsBinaryExpression( @@ -209,9 +239,14 @@ abstract class AbstractExpressionMixin implements ExpressionBuilder { ); } + @override + ExpressionBuilder increment([bool prefix = false]) { + return new _IncrementExpression(this, prefix); + } + @override ExpressionBuilder identical(ExpressionBuilder other) { - return lib$core.identical.call([ + return lib$core.identical.call([ this, other, ]); @@ -275,6 +310,12 @@ abstract class ExpressionBuilder /// Returns as an [ExpressionBuilder] dividing by [other]. ExpressionBuilder operator /(ExpressionBuilder other); + /// Returns as an [ExpressionBuilder] `<` by [other]. + ExpressionBuilder operator <(ExpressionBuilder other); + + /// Returns as an [ExpressionBuilder] `>` by [other]. + ExpressionBuilder operator >(ExpressionBuilder other); + /// Returns as an [ExpressionBuilder] `&&` [other]. ExpressionBuilder and(ExpressionBuilder other); @@ -323,6 +364,9 @@ abstract class ExpressionBuilder /// Returns as a [StatementBuilder] yielding this one. StatementBuilder asYieldStar(); + /// Returns as a [WhileStatementBuilder] with this as the condition. + WhileStatementBuilder asWhile({bool asDo: false}); + /// Returns an [Expression] AST representing the builder. Expression buildExpression([Scope scope]); @@ -337,12 +381,18 @@ abstract class ExpressionBuilder Iterable create(ExpressionBuilder self), ); + /// Returns as an [ExpressionBuilder] decrementing this expression. + ExpressionBuilder decrement(); + /// Returns as an [ExpressionBuilder] comparing using `==` against [other]. ExpressionBuilder equals(ExpressionBuilder other); /// Returns as an [ExpressionBuilder] comparing using `identical`. ExpressionBuilder identical(ExpressionBuilder other); + /// Returns as an [ExpressionBuilder] incrementing this expression. + ExpressionBuilder increment([bool prefix = false]); + /// Returns as an [InvocationBuilder] on [method] of this expression. InvocationBuilder invoke( String method, @@ -476,6 +526,15 @@ ExpressionBuilder _expressionify(v) { throw new ArgumentError('Could not expressionify $v'); } +class _SuperExpression extends Object + with AbstractExpressionMixin, TopLevelMixin { + @override + AstNode buildAst([Scope scope]) => buildExpression(scope); + + @override + Expression buildExpression([_]) => astFactory.superExpression($super); +} + class _TypedListExpression extends Object with AbstractExpressionMixin, TopLevelMixin { static List _toExpression(Iterable values) { diff --git a/pkgs/code_builder/lib/src/builders/expression/operators.dart b/pkgs/code_builder/lib/src/builders/expression/operators.dart index 809f2d159..99bf9eaa4 100644 --- a/pkgs/code_builder/lib/src/builders/expression/operators.dart +++ b/pkgs/code_builder/lib/src/builders/expression/operators.dart @@ -24,3 +24,46 @@ class _AsBinaryExpression extends Object ); } } + +class _DecrementExpression extends Object + with AbstractExpressionMixin, TopLevelMixin { + final ExpressionBuilder _expression; + + _DecrementExpression(this._expression); + + @override + AstNode buildAst([Scope scope]) => buildExpression(scope); + + @override + Expression buildExpression([Scope scope]) { + return astFactory.postfixExpression( + _expression.buildExpression(scope), + $minusMinus, + ); + } +} + +class _IncrementExpression extends Object + with AbstractExpressionMixin, TopLevelMixin { + final ExpressionBuilder _expression; + final bool _prefix; + + _IncrementExpression(this._expression, this._prefix); + + @override + AstNode buildAst([Scope scope]) => buildExpression(scope); + + @override + Expression buildExpression([Scope scope]) { + if (_prefix) { + return astFactory.prefixExpression( + $plusPlus, + _expression.buildExpression(scope), + ); + } + return astFactory.postfixExpression( + _expression.buildExpression(scope), + $plusPlus, + ); + } +} diff --git a/pkgs/code_builder/lib/src/builders/method.dart b/pkgs/code_builder/lib/src/builders/method.dart index f2bbd3c11..44e747369 100644 --- a/pkgs/code_builder/lib/src/builders/method.dart +++ b/pkgs/code_builder/lib/src/builders/method.dart @@ -171,7 +171,7 @@ ConstructorBuilder _constructorImpl({ throw new StateError('Invalid AST type: ${member.runtimeType}'); } } - final constructor = new ConstructorBuilder(name); + final constructor = new ConstructorBuilder(name: name); _addFunctions.forEach((a) => a(constructor)); return constructor; } @@ -186,7 +186,20 @@ abstract class ConstructorBuilder HasStatements, ValidClassMember { /// Create a new [ConstructorBuilder], optionally with a [name]. - factory ConstructorBuilder([String name]) = _NormalConstructorBuilder; + /// + /// Can invoke `super` if [invokeSuper] is set, using super.[superName]. + factory ConstructorBuilder({ + String name, + String superName, + List invokeSuper, + }) = _NormalConstructorBuilder; + + /// Adds a field initializer to this constructor. + void addInitializer( + String fieldName, { + ExpressionBuilder toExpression, + String toParameter, + }); @override void addNamed(ParameterBuilder parameter, {bool asField: false}); @@ -530,9 +543,28 @@ class _NamedParameterWrapper class _NormalConstructorBuilder extends Object with HasAnnotationsMixin, HasParametersMixin, HasStatementsMixin implements ConstructorBuilder { + final _initializers = {}; final String _name; + final String _superName; + final List _superInvocation; - _NormalConstructorBuilder([this._name]); + _NormalConstructorBuilder({ + List invokeSuper, + String name, + String superName, + }) + : _name = name, + _superInvocation = invokeSuper, + _superName = superName; + + @override + void addInitializer( + String fieldName, { + ExpressionBuilder toExpression, + String toParameter, + }) { + _initializers[fieldName] = toExpression ?? reference(toParameter); + } @override ConstructorDeclaration buildAst([Scope scope]) { @@ -540,8 +572,40 @@ class _NormalConstructorBuilder extends Object } @override - ConstructorDeclaration buildConstructor(TypeBuilder returnType, - [Scope scope]) { + ConstructorDeclaration buildConstructor( + TypeBuilder returnType, [ + Scope scope, + ]) { + List initializers; + if (_initializers.isNotEmpty) { + initializers ??= []; + initializers.addAll( + _initializers.keys.map((fieldName) { + return astFactory.constructorFieldInitializer( + null, + null, + astFactory.simpleIdentifier(stringToken(fieldName)), + $equals, + _initializers[fieldName].buildExpression(scope), + ); + }), + ); + } + if (_superInvocation != null) { + initializers ??= []; + initializers.add(astFactory.superConstructorInvocation( + $super, + _superName != null ? $period : null, + _superName != null + ? astFactory.simpleIdentifier(stringToken(_superName)) + : null, + astFactory.argumentList( + $openParen, + _superInvocation.map((e) => e.buildExpression(scope)).toList(), + $closeParen, + ), + )); + } return astFactory.constructorDeclaration( null, buildAnnotations(scope), @@ -552,8 +616,8 @@ class _NormalConstructorBuilder extends Object _name != null ? $period : null, _name != null ? stringIdentifier(_name) : null, buildParameterList(scope), - null, - null, + initializers != null && initializers.isNotEmpty ? $semicolon : null, + initializers, null, !hasStatements ? astFactory.emptyFunctionBody($semicolon) diff --git a/pkgs/code_builder/lib/src/builders/parameter.dart b/pkgs/code_builder/lib/src/builders/parameter.dart index 5f2cc31a8..a3443c1db 100644 --- a/pkgs/code_builder/lib/src/builders/parameter.dart +++ b/pkgs/code_builder/lib/src/builders/parameter.dart @@ -100,6 +100,9 @@ abstract class ParameterBuilder /// Returns a positional [FormalParameter] AST representing the builder. FormalParameter buildPositional(bool field, [Scope scope]); + + /// Name of the parameter. + String get name; } /// A marker interface for an AST that could be added to [ParameterBuilder]. @@ -140,6 +143,9 @@ class _OptionalParameterBuilder extends Object _expression?.buildExpression(scope), ); } + + @override + String get name => _parameter.name; } class _ParameterPair { @@ -165,15 +171,15 @@ class _ParameterPair { class _SimpleParameterBuilder extends Object with HasAnnotationsMixin implements ParameterBuilder { - final String _name; + @override + final String name; final TypeBuilder _type; _SimpleParameterBuilder( - String name, { + this.name, { TypeBuilder type, }) - : _name = name, - _type = type; + : _type = type; @override ParameterBuilder asOptional([ExpressionBuilder defaultTo]) { @@ -198,7 +204,7 @@ class _SimpleParameterBuilder extends Object _type?.buildType(scope), $this, $period, - stringIdentifier(_name), + stringIdentifier(name), null, null, ); @@ -208,7 +214,7 @@ class _SimpleParameterBuilder extends Object buildAnnotations(scope), null, _type?.buildType(scope), - stringIdentifier(_name), + stringIdentifier(name), ); } } diff --git a/pkgs/code_builder/lib/src/builders/statement.dart b/pkgs/code_builder/lib/src/builders/statement.dart index 85d2befa2..8f7e6a22c 100644 --- a/pkgs/code_builder/lib/src/builders/statement.dart +++ b/pkgs/code_builder/lib/src/builders/statement.dart @@ -9,8 +9,12 @@ import 'package:code_builder/src/builders/shared.dart'; import 'package:code_builder/src/builders/statement/if.dart'; import 'package:code_builder/src/tokens.dart'; +export 'package:code_builder/src/builders/statement/for.dart' + show ForStatementBuilder; export 'package:code_builder/src/builders/statement/if.dart' show IfStatementBuilder, elseIf, elseThen, ifThen; +export 'package:code_builder/src/builders/statement/while.dart' + show WhileStatementBuilder; /// An [AstBuilder] that can add [StatementBuilder]. abstract class HasStatements implements AstBuilder { diff --git a/pkgs/code_builder/lib/src/builders/statement/for.dart b/pkgs/code_builder/lib/src/builders/statement/for.dart new file mode 100644 index 000000000..58bf8d869 --- /dev/null +++ b/pkgs/code_builder/lib/src/builders/statement/for.dart @@ -0,0 +1,121 @@ +// Copyright (c) 2016, 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:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/standard_ast_factory.dart'; +import 'package:code_builder/src/builders/expression.dart'; +import 'package:code_builder/src/builders/shared.dart'; +import 'package:code_builder/src/builders/statement.dart'; +import 'package:code_builder/src/tokens.dart'; + +abstract class ForStatementBuilder implements HasStatements, StatementBuilder { + factory ForStatementBuilder( + String identifier, + ExpressionBuilder initializer, + ExpressionBuilder condition, + List updaters, + ) = _ForLoopStatementBuilder; + + factory ForStatementBuilder.forEach( + String identifier, + ExpressionBuilder iterable, { + bool asAwait: false, + bool asFinal: false, + }) { + return new _ForIteratorStatementBuilder( + asAwait, + asFinal, + identifier, + iterable, + ); + } +} + +class _ForIteratorStatementBuilder extends Object + with HasStatementsMixin, TopLevelMixin + implements ForStatementBuilder { + final bool _asAwait; + final bool _asFinal; + final String _identifier; + final ExpressionBuilder _iterable; + + _ForIteratorStatementBuilder( + this._asAwait, + this._asFinal, + this._identifier, + this._iterable, + ); + + @override + AstNode buildAst([Scope scope]) => buildStatement(scope); + + @override + Statement buildStatement([Scope scope]) { + return astFactory.forEachStatementWithDeclaration( + _asAwait ? $await : null, + $for, + $openParen, + astFactory.declaredIdentifier( + null, + null, + _asFinal ? $final : $var, + null, + astFactory.simpleIdentifier(stringToken(_identifier)), + ), + $in, + _iterable.buildExpression(scope), + $closeParen, + buildBlock(scope), + ); + } +} + +class _ForLoopStatementBuilder extends Object + with HasStatementsMixin, TopLevelMixin + implements ForStatementBuilder { + final String _identifier; + final ExpressionBuilder _initializer; + final ExpressionBuilder _condition; + final List _updaters; + + _ForLoopStatementBuilder( + this._identifier, + this._initializer, + this._condition, + this._updaters, + ); + + @override + AstNode buildAst([Scope scope]) => buildStatement(scope); + + @override + Statement buildStatement([Scope scope]) { + return astFactory.forStatement( + $for, + $openParen, + astFactory.variableDeclarationList( + null, + null, + $var, + null, + [ + astFactory.variableDeclaration( + astFactory.simpleIdentifier( + stringToken(_identifier), + ), + $equals, + _initializer.buildExpression(scope), + ), + ], + ), + null, + $semicolon, + _condition.buildExpression(scope), + $semicolon, + _updaters.map((e) => e.buildExpression(scope)).toList(), + $closeParen, + buildBlock(scope), + ); + } +} diff --git a/pkgs/code_builder/lib/src/builders/statement/while.dart b/pkgs/code_builder/lib/src/builders/statement/while.dart new file mode 100644 index 000000000..ba1cb622c --- /dev/null +++ b/pkgs/code_builder/lib/src/builders/statement/while.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2016, 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:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/standard_ast_factory.dart'; +import 'package:code_builder/src/builders/expression.dart'; +import 'package:code_builder/src/builders/shared.dart'; +import 'package:code_builder/src/builders/statement.dart'; +import 'package:code_builder/src/tokens.dart'; + +class WhileStatementBuilder extends HasStatementsMixin + with TopLevelMixin + implements StatementBuilder { + final bool _asDo; + final ExpressionBuilder _condition; + + WhileStatementBuilder(this._asDo, this._condition); + + @override + AstNode buildAst([Scope scope]) => buildStatement(scope); + + @override + Statement buildStatement([Scope scope]) { + if (_asDo) { + return astFactory.doStatement( + $do, + buildBlock(scope), + $while, + $openParen, + _condition.buildExpression(scope), + $closeParen, + $semicolon, + ); + } + return astFactory.whileStatement( + $while, + $openParen, + _condition.buildExpression(scope), + $closeParen, + buildBlock(scope), + ); + } +} diff --git a/pkgs/code_builder/lib/src/tokens.dart b/pkgs/code_builder/lib/src/tokens.dart index 01b42da9b..84fbc0631 100644 --- a/pkgs/code_builder/lib/src/tokens.dart +++ b/pkgs/code_builder/lib/src/tokens.dart @@ -47,6 +47,9 @@ final Token $deferred = new KeywordToken(Keyword.DEFERRED, 0); /// The `/` token. final Token $divide = new Token(TokenType.SLASH, 0); +/// The `do` keyword. +final Token $do = new KeywordToken(Keyword.DO, 0); + /// The `else` token. final Token $else = new KeywordToken(Keyword.ELSE, 0); @@ -65,15 +68,24 @@ final Token $false = new KeywordToken(Keyword.FALSE, 0); /// The `final` token. final Token $final = new KeywordToken(Keyword.FINAL, 0); +/// The `for` keyword. +final Token $for = new KeywordToken(Keyword.FOR, 0); + /// The `>` token. final Token $gt = new Token(TokenType.GT, 0); /// The `if` token. final Token $if = new KeywordToken(Keyword.IF, 0); +/// The `super` keyword. +final Token $super = new KeywordToken(Keyword.SUPER, 0); + /// The `yield` token. final Token $yield = new StringToken(TokenType.KEYWORD, 'yield', 0); +/// The `while` keyword. +final Token $while = new KeywordToken(Keyword.WHILE, 0); + // Simple tokens /// The `&&` token. @@ -88,6 +100,9 @@ final Token $hide = new StringToken(TokenType.KEYWORD, 'hide', 0); /// The `implements` token. final Token $implements = new KeywordToken(Keyword.IMPLEMENTS, 0); +/// The `in` token. +final Token $in = new KeywordToken(Keyword.IN, 0); + /// The `library` token. final Token $library = new KeywordToken(Keyword.LIBRARY, 0); @@ -97,6 +112,9 @@ final Token $lt = new Token(TokenType.LT, 0); /// The `-` token. final Token $minus = new Token(TokenType.MINUS, 0); +/// The `--` token. +final Token $minusMinus = new Token(TokenType.MINUS_MINUS, 0); + /// The `*` token. final Token $multiply = new Token(TokenType.STAR, 0); @@ -139,6 +157,9 @@ final Token $period = new Token(TokenType.PERIOD, 0); /// The `+` token. final Token $plus = new Token(TokenType.PLUS, 0); +/// The `++` token. +final Token $plusPlus = new Token(TokenType.PLUS_PLUS, 0); + /// The `return` token. final Token $return = new KeywordToken(Keyword.RETURN, 0); diff --git a/pkgs/code_builder/pubspec.yaml b/pkgs/code_builder/pubspec.yaml index 5b84babd5..6f46486e3 100644 --- a/pkgs/code_builder/pubspec.yaml +++ b/pkgs/code_builder/pubspec.yaml @@ -1,5 +1,5 @@ name: code_builder -version: 1.0.0-alpha+9 +version: 1.0.0-beta description: A fluent API for generating Dart code author: Dart Team homepage: https://github.com/dart-lang/code_builder diff --git a/pkgs/code_builder/test/builders/class_test.dart b/pkgs/code_builder/test/builders/class_test.dart index 40fe307dc..776ee4fec 100644 --- a/pkgs/code_builder/test/builders/class_test.dart +++ b/pkgs/code_builder/test/builders/class_test.dart @@ -101,6 +101,21 @@ void main() { ); }); + test('should emit a class with a constructor with initializers', () { + expect( + clazz('Animal', [ + new ConstructorBuilder( + invokeSuper: const [], + )..addInitializer('name', toParameter: 'other'), + ]), + equalsSource(r''' + class Animal { + Animal() : name = other, super(); + } + '''), + ); + }); + test('should emit a class with fields', () { expect( clazz('Animal', [ diff --git a/pkgs/code_builder/test/builders/statement_test.dart b/pkgs/code_builder/test/builders/statement_test.dart index f76680892..7f0384b2b 100644 --- a/pkgs/code_builder/test/builders/statement_test.dart +++ b/pkgs/code_builder/test/builders/statement_test.dart @@ -95,4 +95,48 @@ void main() { ); }); }); + + group('for statements', () { + test('should emit a simple for-loop', () { + expect( + new ForStatementBuilder( + 'i', + literal(0), + reference('i') < reference('items').property('length'), + [ + reference('i').increment(), + ], + ), + equalsSource(r''' + for (var i = 0; i < items.length; i++) {} + '''), + ); + }); + + test('should emit a simple for-each loop', () { + expect( + new ForStatementBuilder.forEach( + 'item', + reference('items'), + ), + equalsSource(r''' + for (var item in items) {} + '''), + ); + }); + }); + + group('while loop', () { + test('should emit a simple while loop', () { + expect(literal(true).asWhile(), equalsSource(r''' + while(true) {} + ''')); + }); + + test('should emit a simple do-while loop', () { + expect(literal(true).asWhile(asDo: true), equalsSource(r''' + do {} while (true); + ''')); + }); + }); }