Skip to content

[code_builder] Add control-flow support #2135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
16e8e34
[code_builder] add control-flow expressions via `ControlExpression`
one23four56 Jul 24, 2025
cbbb7ee
[code_builder] fix typos in `expression_test` and changelog
one23four56 Jul 24, 2025
1754964
[code_builder] feat: add control-flow loops
one23four56 Jul 24, 2025
ec35a89
[code_builder] chore: rebuild generated files with newer `built_value…
one23four56 Jul 24, 2025
6d152c4
[code_builder] style: follow commonmark
one23four56 Jul 24, 2025
993ca06
[code_builder] feat: support if/else trees
one23four56 Jul 26, 2025
415bc29
[code_builder] feat: support try/catch blocks
one23four56 Jul 26, 2025
32797a0
[code_builder] refactor: split up control.dart
one23four56 Jul 27, 2025
b39e415
[code_builder] feat: support switch statements
one23four56 Jul 27, 2025
8b9dbfc
[code_builder] feat: support `switch` expressions
one23four56 Jul 28, 2025
4ef3b88
[code_builder] feat: support collection control-flow expressions
one23four56 Jul 28, 2025
da9b254
update readme and delete temp files
one23four56 Jul 29, 2025
76e4560
update readme and delete temp files
one23four56 Jul 29, 2025
25f0368
allow `catch` omission and update defaults
one23four56 Jul 29, 2025
7f0b0d1
Merge branch 'main' into main
one23four56 Jul 29, 2025
4c02606
refactor branches
one23four56 Jul 30, 2025
ac79fa1
Merge branch 'main' of https://github.com/one23four56/tools
one23four56 Jul 30, 2025
3435a07
- drop ignores
one23four56 Aug 9, 2025
eecb6d5
Merge branch 'main' into main
one23four56 Aug 9, 2025
ab72c8b
downgrade `build` to 2.4.2
one23four56 Aug 18, 2025
4bb0562
Merge branch 'main' into main
one23four56 Aug 18, 2025
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
2 changes: 1 addition & 1 deletion pkgs/code_builder/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
.dart_tool
.packages
.pub
pubspec.lock
pubspec.lock
192 changes: 120 additions & 72 deletions pkgs/code_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,59 @@
## 4.10.2-wip
## 4.11.0-wip

* Support `Expression.newInstanceNamed` with empty name
* Consistently add blank lines between `=>` in class-like definitions.
* Fixed bug: Fields declared with `static` and `external` now produce code with
correct order

* Add `ControlFlow` extension on `Expression` to support control-flow helper functions.
* Add `Expression.yielded` (via ext.)
* Add `Expression.yieldStarred` (via ext.)
* Add `Expression.ifThen` (via ext.)
* Add `Expression.ifThenReturn` (via ext.)
* Add `Expression.loopWhile` (via ext.)
* Add `Expression.loopDoWhile` (via ext.)
* Add `Expression.loopForIn` (via ext.)

* Add static keyword helper functions to `ControlFlow`.
* Add `ControlFlow.breakVoid`
* Add `ControlFlow.breakLabel`
* Add `ControlFlow.continueVoid`
* Add `ControlFlow.continueLabel`
* Add `ControlFlow.returnVoid`
* Add `ControlFlow.rethrowVoid`

* Support emitting collection control-flow expressions via static methods on `ControlFlow`.
* Add `ControlFlow.collectionIf`
* Add `ControlFlow.collectionElse`
* Add `ControlFlow.collectionFor`
* Add `ControlFlow.collectionForIn`
* Add `ControlFlow.ifCase`
* Update literal collection visitors to support chaining.

* Support emitting control-flow loops.
* Add `ForLoop` and `ForLoopBuilder` for traditional `for` loops.
* Add `ForInLoop` and `ForInLoopBuilder` for `for-in` and `await-for` loops.
* Add `WhileLoop` and `WhileLoopBuilder` for `while` and `do-while` loops.

* Support emitting `if` statements and `if`/`else if`/`else` trees.
* Add `Conditional` and `ConditionalBuilder` for conditional trees.
* Add `BranchBuilder` for building `Conditional` branches.

* Support emitting `try`/`catch`/`finally` blocks.
* Add `CatchBlock` and `CatchBlockBuilder` for catch clauses.
* Add `TryCatch` and `TryCatchBuilder` for try/catch blocks.

* Support emitting `switch` statements and expressions.
* Add `Case` and `CaseBuilder` for creating `switch` cases.
* Add `SwitchExpression` and `SwitchExpressionBuilder` for `switch` expressions.
* Add `SwitchStatement` and `SwitchStatementBuilder` for `switch` statements.
* Add `Expression.wildcard` static constant for wildcard (`_`) expressions.

* Simplify usage examples on the README.

* Support `Expression.newInstanceNamed` with empty name.

* Fixed bug: Fields declared with `static` and `external` now produce code with correct order.

* Upgrade `dart_style` and `source_gen` to remove `package:macros` dependency.

* Require Dart `^3.6.0` due to the upgrades.

## 4.10.1
Expand Down Expand Up @@ -158,7 +207,7 @@ void main() {
## 3.4.1

* Fix confusing mismatch description from `equalsDart`.
https://github.com/dart-lang/code_builder/issues/293
<https://github.com/dart-lang/code_builder/issues/293>
Copy link
Member

Choose a reason for hiding this comment

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

avoid other changes to this file. it makes it hard to review!

Copy link
Author

Choose a reason for hiding this comment

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

apologies, that was my formatter as i inadvertently left format on save enabled


## 3.4.0

Expand Down Expand Up @@ -211,7 +260,6 @@ void main() {
* `Expression.asA` is now wrapped with parenthesis so that further calls may be
made on it as an expression.


## 3.1.0

* Added `Expression.asA` for creating explicit casts:
Expand Down Expand Up @@ -258,7 +306,7 @@ void main() {

## 2.4.0

* Add `equalTo`, `notEqualTo`, `greaterThan`, `lessThan`, `greateOrEqualTo`, and
* Add `equalTo`, `notEqualTo`, `greaterThan`, `lessThan`, `greaterOrEqualTo`, and
`lessOrEqualTo` to `Expression`.

## 2.3.0
Expand Down Expand Up @@ -348,7 +396,7 @@ void main() {
```

* Added `nullSafeProperty` to `Expression` to access properties with `?.`
* Added `conditional` to `Expression` to use the ternary operator `? : `
* Added `conditional` to `Expression` to use the ternary operator `? :`
* Methods taking `positionalArguments` accept `Iterable<Expression>`
* **BUG FIX**: Parameters can take a `FunctionType` as a `type`.
`Reference.type` now returns a `Reference`. Note that this change is
Expand Down Expand Up @@ -574,7 +622,7 @@ final animal = new Class((b) => b
## 2.0.0-alpha

* Complete re-write to not use `package:analyzer`.
* Code generation now properly uses the _builder_ pattern (via `built_value`).
* Code generation now properly uses the *builder* pattern (via `built_value`).
* See examples and tests for details.

## 1.0.4
Expand Down Expand Up @@ -608,38 +656,38 @@ that the entire Dart language is buildable with our API, though.

**Contributions are welcome.**

- Exposed `uri` in `ImportBuilder`, `ExportBuilder`, and `Part[Of]Builder`.
* Exposed `uri` in `ImportBuilder`, `ExportBuilder`, and `Part[Of]Builder`.

## 1.0.0-beta+7

- Added `ExpressionBuilder#ternary`.
* Added `ExpressionBuilder#ternary`.

## 1.0.0-beta+6

- Added `TypeDefBuilder`.
- Added `FunctionParameterBuilder`.
- Added `asAbstract` to various `MethodBuilder` constructors.
* Added `TypeDefBuilder`.
* Added `FunctionParameterBuilder`.
* Added `asAbstract` to various `MethodBuilder` constructors.

## 1.0.0-beta+5

- Re-published the package without merge conflicts.
* Re-published the package without merge conflicts.

## 1.0.0-beta+4

- Renamed `PartBuilder` to `PartOfBuilder`.
- Added a new class, `PartBuilder`, to represent `part '...dart'` directives.
- Added the `HasAnnotations` interface to all library/part/directive builders.
- Added `asFactory` and `asConst` to `ConstructorBuilder`.
- Added `ConstructorBuilder.redirectTo` for a redirecting factory constructor.
- Added a `name` getter to `ReferenceBuilder`.
- Supplying an empty constructor name (`''`) is equivalent to `null` (default).
- Automatically encodes string literals with multiple lines as `'''`.
- Added `asThrow` to `ExpressionBuilder`.
- Fixed a bug that prevented `FieldBuilder` from being used at the top-level.
* Renamed `PartBuilder` to `PartOfBuilder`.
* Added a new class, `PartBuilder`, to represent `part '...dart'` directives.
* Added the `HasAnnotations` interface to all library/part/directive builders.
* Added `asFactory` and `asConst` to `ConstructorBuilder`.
* Added `ConstructorBuilder.redirectTo` for a redirecting factory constructor.
* Added a `name` getter to `ReferenceBuilder`.
* Supplying an empty constructor name (`''`) is equivalent to `null` (default).
* Automatically encodes string literals with multiple lines as `'''`.
* Added `asThrow` to `ExpressionBuilder`.
* Fixed a bug that prevented `FieldBuilder` from being used at the top-level.

## 1.0.0-beta+3

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

```dart
expect(
Expand All @@ -652,7 +700,7 @@ expect(
);
```

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

```dart
expect(
Expand All @@ -665,7 +713,7 @@ expect(

### BREAKING CHANGES

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

```dart
expect(
Expand All @@ -676,7 +724,7 @@ expect(
);
```

- Renamed `named` parameter to `namedArguments`:
* Renamed `named` parameter to `namedArguments`:

```dart
expect(
Expand All @@ -698,25 +746,25 @@ expect(

Avoid creating symbols that can collide with the Dart language:

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

## 1.0.0-beta+1

- Add support for `switch` statements
- Add support for a raw expression and statement
- `new ExpressionBuilder.raw(...)`
- `new StatemnetBuilder.raw(...)`
* Add support for `switch` statements
* Add support for a raw expression and statement
* `new ExpressionBuilder.raw(...)`
* `new StatementBuilder.raw(...)`

This should help cover any cases not covered with builders today.

- Allow referring to a `ClassBuilder` and `TypeBuilder` as an expression
- Add support for accessing the index `[]` operator on an expression
* Allow referring to a `ClassBuilder` and `TypeBuilder` as an expression
* Add support for accessing the index `[]` operator on an expression

### BREAKING CHANGES

- Changed `ExpressionBuilder.asAssign` to always take an `ExpressionBuilder` as
* Changed `ExpressionBuilder.asAssign` to always take an `ExpressionBuilder` as
target and removed the `value` property. Most changes are pretty simple, and
involve just using `reference(...)`. For example:

Expand All @@ -728,34 +776,34 @@ literal(true).asAssign(reference('flag'))

## 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
- 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`
* Add support for `async`, `sync`, `sync*` functions
* Add support for expression `asAwait`, `asYield`, `asYieldStar`
* Add `toExportBuilder` and `toImportBuilder` to types and references
* 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

- Make use of the new analyzer APIs in preparation for analyzer version 0.30.
* Make use of the new analyzer APIs in preparation for analyzer version 0.30.

## 1.0.0-alpha+6

- `MethodBuilder.closure` emits properly as a top-level function
* `MethodBuilder.closure` emits properly as a top-level function

## 1.0.0-alpha+5

- MethodBuilder with no statements will create an empty block instead of
* MethodBuilder with no statements will create an empty block instead of
a semicolon.

```dart
// main() {}
method('main')
```

- Fix lambdas and closures to not include a trailing semicolon when used
* Fix lambdas and closures to not include a trailing semicolon when used
as an expression.

```dart
Expand All @@ -765,29 +813,29 @@ method('main')

## 1.0.0-alpha+4

- Add support for the latest `pkg/analyzer`.
* Add support for the latest `pkg/analyzer`.

## 1.0.0-alpha+3

- BREAKING CHANGE: Added generics support to `TypeBuilder`:
* BREAKING CHANGE: Added generics support to `TypeBuilder`:

`importFrom` becomes a _named_, not a positional argument, and the named
`importFrom` becomes a *named*, not a positional argument, and the named
argument `genericTypes` is added (`Iterable<TypeBuilder>`).

```dart
// List<String>
new TypeBuilder('List', genericTypes: [reference('String')])
```

- Added generic support to `ReferenceBuilder`:
* Added generic support to `ReferenceBuilder`:

```dart
// List<String>
reference('List').toTyped([reference('String')])
```

- Fixed a bug where `ReferenceBuilder.buildAst` was not implemented
- Added `and` and `or` methods to `ExpressionBuilder`:
* Fixed a bug where `ReferenceBuilder.buildAst` was not implemented
* Added `and` and `or` methods to `ExpressionBuilder`:

```dart
// true || false
Expand All @@ -797,7 +845,7 @@ literal(true).or(literal(false));
literal(true).and(literal(false));
```

- Added support for creating closures - `MethodBuilder.closure`:
* Added support for creating closures - `MethodBuilder.closure`:

```dart
// () => true
Expand All @@ -809,21 +857,21 @@ new MethodBuilder.closure(

## 1.0.0-alpha+2

- Added `returnVoid` to well, `return;`
- Added support for top-level field assignments:
* Added `returnVoid` to well, `return;`
* Added support for top-level field assignments:

```dart
new LibraryBuilder()..addMember(literal(false).asConst('foo'))
```

- Added support for specifying a `target` when using `asAssign`:
* Added support for specifying a `target` when using `asAssign`:

```dart
// Outputs bank.bar = goldBar
reference('goldBar').asAssign('bar', target: reference('bank'))
```

- Added support for the cascade operator:
* Added support for the cascade operator:

```dart
// Outputs foo..doThis()..doThat()
Expand All @@ -833,7 +881,7 @@ reference('foo').cascade((c) => <ExpressionBuilder> [
]);
```

- Added support for accessing a property
* Added support for accessing a property

```dart
// foo.bar
Expand All @@ -842,25 +890,25 @@ reference('foo').property('bar');

## 1.0.0-alpha+1

- Slight updates to confusing documentation.
- Added support for null-aware assignments.
- Added `show` and `hide` support to `ImportBuilder`
- Added `deferred` support to `ImportBuilder`
- Added `ExportBuilder`
- Added `list` and `map` literals that support generic types
* Slight updates to confusing documentation.
* Added support for null-aware assignments.
* Added `show` and `hide` support to `ImportBuilder`
* Added `deferred` support to `ImportBuilder`
* Added `ExportBuilder`
* Added `list` and `map` literals that support generic types

## 1.0.0-alpha

- Large refactor that makes the library more feature complete.
* Large refactor that makes the library more feature complete.

## 0.1.1

- Add the concept of `Scope` and change `toAst` to support it
* Add the concept of `Scope` and change `toAst` to support it

Now your entire AST tree can be scoped and import directives
automatically added to a `LibraryBuilder` for you if you use
`LibraryBuilder.scope`.

## 0.1.0

- Initial version
* Initial version
Loading