visitSwitch method
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();
}