run method

  1. @override
FutureOr<ASTValue> run(
  1. VMContext parentContext,
  2. ASTRunStatus runStatus
)
override

Implementation

@override
FutureOr<ASTValue> run(
  VMContext parentContext,
  ASTRunStatus runStatus,
) async {
  var context = VMScopeContext(parentContext.block, parent: parentContext);
  var prevContext = VMContext.setCurrent(context);

  try {
    var switchValue = await expression.run(context, runStatus);
    var rawSwitch = await switchValue.getValue(context);

    // Find the matching case, or fall back to `default`.
    var startIndex = -1;
    for (var i = 0; i < cases.length; ++i) {
      var c = cases[i];
      if (c.isDefault) continue;
      var caseValue = await c.value!.run(context, runStatus);
      var rawCase = await caseValue.getValue(context);
      if (rawSwitch == rawCase) {
        startIndex = i;
        break;
      }
    }

    if (startIndex < 0) {
      startIndex = cases.indexWhere((c) => c.isDefault);
    }

    if (startIndex < 0) return ASTValueVoid.instance;

    if (!fallThrough) {
      // Only the matched clause runs (Kotlin `when` / Python `match`).
      await cases[startIndex].block.run(context, runStatus);
      // `break` is implicit here, so consume any that bubbled up.
      if (runStatus.broke) runStatus.broke = false;
      return ASTValueVoid.instance;
    }

    // Fall-through: run from the matched clause onward until break/return.
    for (var i = startIndex; i < cases.length; ++i) {
      await cases[i].block.run(context, runStatus);

      // `return`/`continue` propagate up (e.g. `continue` of an enclosing
      // loop); `break` is consumed here as it targets this switch.
      if (runStatus.returned || runStatus.continued) break;
      if (runStatus.broke) {
        runStatus.broke = false;
        break;
      }
    }
  } finally {
    VMContext.setCurrent(prevContext);
  }

  return ASTValueVoid.instance;
}