visitWhen method

  1. @override
Uint8List visitWhen(
  1. WhenStmt stmt
)
override

Implementation

@override
Uint8List visitWhen(WhenStmt stmt) {
  final bytesBuilder = BytesBuilder();
  bytesBuilder.add(_lineInfo(stmt.line, stmt.column));
  Uint8List? condition;
  if (stmt.condition != null) {
    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();
    if (condition != null) {
      if (ast is CommaExpr) {
        caseBytesBuilder.addByte(WhenCaseTypeCode.eigherEquals);
        final bytes = visitCommaExpr(ast);
        caseBytesBuilder.add(bytes);
      } else if (ast is InOfExpr) {
        caseBytesBuilder.addByte(WhenCaseTypeCode.elementIn);
        Uint8List bytes;
        if (ast.valueOf) {
          final getValues = MemberExpr(ast.collection,
              IdentifierExpr(_lexicon.idCollectionValues, isLocal: false));
          bytes = compileAST(getValues, endOfExec: true);
        } else {
          bytes = compileAST(ast.collection, endOfExec: true);
        }
        caseBytesBuilder.add(bytes);
      } else {
        caseBytesBuilder.addByte(WhenCaseTypeCode.equals);
        final bytes = compileAST(ast, endOfExec: true);
        caseBytesBuilder.add(bytes);
      }
    } else {
      caseBytesBuilder.addByte(WhenCaseTypeCode.equals);
      final bytes = compileAST(ast, endOfExec: true);
      caseBytesBuilder.add(bytes);
    }
    cases.add(caseBytesBuilder.toBytes());
    final branchBytes = compileAST(stmt.cases[ast]!);
    branches.add(branchBytes);
  }
  bytesBuilder.addByte(HTOpCode.anchor);
  if (condition != null) {
    bytesBuilder.add(condition);
  }
  bytesBuilder.addByte(HTOpCode.whenStmt);
  bytesBuilder.addByte(condition != null ? 1 : 0);
  bytesBuilder.addByte(cases.length);
  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);
  // calculate the length of the code since the anchor,
  // for goto the specific location of branches.
  var offsetIp = (condition?.length ?? 0) + 3;
  // calculate the length of all cases end else jump code first
  for (final expr in cases) {
    offsetIp += expr.length + 3;
  }
  offsetIp += 3;
  // for each case, if true, will jump to a certain branch.
  for (var i = 0; i < cases.length; ++i) {
    final expr = cases[i];
    bytesBuilder.add(expr);
    bytesBuilder.addByte(HTOpCode.goto);
    bytesBuilder.add(_uint16(offsetIp + caseJumpIps[i]));
  }
  bytesBuilder.addByte(HTOpCode.goto);
  bytesBuilder.add(_uint16(offsetIp + curBranchIp));
  // for each branch, after execution, will jump to end of statement.
  for (var i = 0; i < branches.length; ++i) {
    bytesBuilder.add(branches[i]);
    bytesBuilder.addByte(HTOpCode.goto);
    bytesBuilder.add(_uint16(offsetIp + endIp));
  }
  if (elseBranch != null) {
    bytesBuilder.add(elseBranch);
  }
  return bytesBuilder.toBytes();
}