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