Skip to content
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

Add ability to generate if-else blocks #834

Open
filiph opened this issue Aug 10, 2018 · 6 comments
Open

Add ability to generate if-else blocks #834

filiph opened this issue Aug 10, 2018 · 6 comments
Labels
good first issue A good starting issue for contributors (issues with this label will appear in /contribute) package:code_builder type-enhancement A request for a change that isn't a bug

Comments

@filiph
Copy link
Contributor

filiph commented Aug 10, 2018

A previous version had .asIf() for building statements like

if (something) {
  // ...
}

As far as I know, the only way to do these with current API is to write this manually via Code(...).

@matanlurey
Copy link
Contributor

The problem with builders for statements is there are so many, and it is hard to cover everything.

Happy to accept PRs though for statements you feel add value!

@matanlurey matanlurey added the good first issue A good starting issue for contributors (issues with this label will appear in /contribute) label Aug 10, 2018
@filiph
Copy link
Contributor Author

filiph commented Aug 10, 2018

Hmm, good point.

Maybe there a way to just let folks built their own statements (like the one above) in a safer way than right now?

Right now, I do something like this:

final conditionString = condition.accept(_dartEmitter).toString();
final returnStatement = literal(returnValue).returned.statement;
final returnString = returnStatement.accept(_dartEmitter).toString();
return Code('if ($conditionString) { $returnString }');

(_dartEmitter is a private member of a class that does not end up building the final code, so it seems a bit out of place here.)

Would it be better to have something like:

final buf = CodeBuffer()
  ..addString('if (')
  ..addExpression(condition)
  ..addString(') {')
  ..addStatement(literal(returnValue).returned)
  ..addString('}');
return buf.build();

Eh. Not sure if this is any better. What I was driving at is a way not to use DartEmitter until the last step. To keep the expressions and statements in their semantic form (as opposed to a string) as long as possible, and yet have the flexibility to just write stuff directly.

@eredo
Copy link
Contributor

eredo commented Sep 20, 2018

Just came across this issue and I was thinking about something like this:

CompountStatementBuilder()
  ..addStatement(refer('myBool').eq(literal('1')).asIf())
  ..addBlock(BlockBuilder()
    ..addStatement(literal(returnValue).returned.statement)
  )
  ..followedBy(CompountStatementBuilder()
    ..addStatement(literalElse)
    ..addBlock(/* .. */));

CompountStatementBuilder()
  ..addStatement(refer('myArray').asFor(refer('item')))
  ..addBlock(/* .. */);

CompountStatementBuilder()
  ..addStatement(literalTry)
  ..addBlock(/* .. */)
  // Maybe use builder callback directly for ease of use?
  ..followedBy((b) => b
    ..addStatement(literalCatch)
    ..addBlock(/* .. */));

Happy to setup a PR.

@devoncarew devoncarew added the type-enhancement A request for a change that isn't a bug label Aug 7, 2023
@TekExplorer
Copy link

TekExplorer commented Dec 15, 2023

I created a helper method like so:

Block ifStatement(
  Expression conditional,
  Code body, [
  bool singleLine = false,
]) =>
    Block.of([
      Code('if ('),
      conditional.code,
      Code(') {'),
      body,
      Code('}'),
    ]);

I even have one for try catch thats a bit more complicated

Block tryStatement({
  required Code try$,
  List<CatchClause> clauses = const [],
  Catch? catch$,
  Code? finally$,
}) {
  if (clauses.isEmpty && catch$ == null && finally$ == null) {
    throw ArgumentError(
        r'Must provide at least one clause such as in `clauses`, `catch$`, or `finally$`');
  }
  return Block((b) {
    b.statements.add(Code('try {'));
    b.statements.add(try$);
    b.statements.add(Code('}'));

    // on X {}

    // on X catch (e) {}
    // on X catch (e, s) {}

    // catch (e) {}
    // catch (e, s) {}
    for (final clause in clauses) {
      if (clause.on case final on) {
        b.statements.add(Code('on '));
        b.statements.add(on.code);
      }
      if (clause.catch$) {
        b.statements.add(Code('catch (e, s)'));
      }
      b.statements.add(Code('{'));
      b.statements.add(clause.body(refer('e'), refer('s')));
      b.statements.add(Code('}'));
    }

    if (catch$ != null) {
      b.statements.add(Code('catch (e, s) {'));
      b.statements.add(catch$.body(refer('e'), refer('s')));
      b.statements.add(Code('}'));
    }

    if (finally$ != null) {
      b.statements.add(Code('finally {'));
      b.statements.add(finally$);
      b.statements.add(Code('}'));
    }
  });
}

class CatchClause {
  final CatchBodyBuilder body;

  final Reference on;
  final bool catch$;

  CatchClause(
    Code body, {
    required this.on,
  })  : catch$ = false,
        body = ((_, __) => body);

  const CatchClause.catch$(
    this.body, {
    required this.on,
  }) : catch$ = true;
}

class Catch {
  final CatchBodyBuilder body;
  const Catch(this.body);

  static const rethrow$ = Catch(_rethrowBody);
  static Code _rethrowBody(_, __) => refer('rethrow').statement;
}

typedef CatchBodyBuilder = Code Function(Reference error, Reference stackTrace);

(note, i did not implement an option that excludes the stacktrace option)
I believe that both statements need to exist in code_builder in some form, not necessarily like this.

@mosuem mosuem transferred this issue from dart-archive/code_builder Oct 29, 2024
@TekExplorer
Copy link

why did this get moved? I'm a bit confused.

@JonasWanke
Copy link

@TekExplorer code_builder got moved into this repo, see #693 and dart-archive/code_builder#467

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue A good starting issue for contributors (issues with this label will appear in /contribute) package:code_builder type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

7 participants