visitSwitch method

  1. @override
Uint8List visitSwitch(
  1. SwitchStmt stmt
)
override

Implementation

@override
Uint8List visitSwitch(SwitchStmt stmt) {
  final bytesBuilder = BytesBuilder();
  bytesBuilder.add(_lineInfo(stmt.line, stmt.column));
  final hasCondition = stmt.condition != null;
  Uint8List? condition;
  if (hasCondition) {
    condition = compileAST(stmt.condition!);
  }
  final cases = <Uint8List>[];
  final branches = <Uint8List>[];
  Uint8List? elseBranch;
  if (stmt.elseBranch != null) {
    elseBranch = compileAST(stmt.elseBranch!);
  }
  for (final ast in stmt.cases.keys) {
    final caseBytesBuilder = BytesBuilder();
    int matchFlags = hasCondition ? 0x80 : 0;
    int multipleEqualsCount = 0;
    if (ast is ParallelExpr) {
      matchFlags |= HTSwitchCaseTypeCode.multipleEquals;
      multipleEqualsCount = ast.list.length;
      for (final item in ast.list) {
        caseBytesBuilder.add(compileAST(item));
      }
    } else if (ast is InOfExpr) {
      matchFlags |= HTSwitchCaseTypeCode.elementIn;
      final collection = ast.valueOf
          ? MemberExpr(ast.collection,
              IdentifierExpr(_lexicon.idValues, isLocal: false))
          : ast.collection;
      caseBytesBuilder.add(compileAST(collection));
    } else {
      matchFlags |= HTSwitchCaseTypeCode.equals;
      caseBytesBuilder.add(compileAST(ast));
    }
    caseBytesBuilder.addByte(OpCode.matchCase);
    caseBytesBuilder.add(_uint16(3)); // skipDist: skip the goto instruction
    caseBytesBuilder.addByte(matchFlags);
    if (multipleEqualsCount > 0) {
      caseBytesBuilder.addByte(multipleEqualsCount);
    }
    cases.add(caseBytesBuilder.toBytes());
    final branchBytes = compileAST(stmt.cases[ast]!);
    branches.add(branchBytes);
  }
  bytesBuilder.addByte(OpCode.anchor);
  if (condition != null) {
    bytesBuilder.add(condition);
  }
  var curBranchIp = 0;
  var caseJumpIps = List.filled(branches.length, 0);
  for (var i = 1; i < branches.length; ++i) {
    curBranchIp += branches[i - 1].length + 3;
    caseJumpIps[i] = curBranchIp;
  }
  curBranchIp += branches.last.length + 3;
  final endIp = curBranchIp + (elseBranch?.length ?? 0);
  var offsetIp = condition?.length ?? 0;
  for (final expr in cases) {
    offsetIp += expr.length + 3;
  }
  if (hasCondition) offsetIp += 1; // pop
  offsetIp += 3; // default goto
  for (var i = 0; i < cases.length; ++i) {
    final expr = cases[i];
    bytesBuilder.add(expr);
    bytesBuilder.addByte(OpCode.goto);
    bytesBuilder.add(_uint16(offsetIp + caseJumpIps[i]));
  }
  if (hasCondition) {
    bytesBuilder.addByte(OpCode.pop);
  }
  bytesBuilder.addByte(OpCode.goto);
  bytesBuilder.add(_uint16(offsetIp + curBranchIp));
  for (var i = 0; i < branches.length; ++i) {
    bytesBuilder.add(branches[i]);
    bytesBuilder.addByte(OpCode.goto);
    bytesBuilder.add(_uint16(offsetIp + endIp));
  }
  if (elseBranch != null) {
    bytesBuilder.add(elseBranch);
  }
  bytesBuilder.addByte(OpCode.clearAnchor);
  return bytesBuilder.toBytes();
}