// when false <blah>
// end
if (value == null) value = BooleanLiteral.TRUE;
// the CASE instruction
Label endLabel = m.getNewLabel();
boolean hasElse = (caseNode.getElseNode() != null);
Label elseLabel = hasElse ? m.getNewLabel() : null;
Variable result = m.getNewTemporaryVariable();
CaseInstr caseInstr = new CaseInstr(result, value, endLabel);
m.addInstr(caseInstr);
// lists to aggregate variables and bodies for whens
List<Operand> variables = new ArrayList<Operand>();
List<Label> labels = new ArrayList<Label>();
Map<Label, Node> bodies = new HashMap<Label, Node>();
// build each "when"
for (Node aCase : caseNode.getCases().childNodes()) {
WhenNode whenNode = (WhenNode)aCase;
Label bodyLabel = m.getNewLabel();
if (whenNode.getExpressionNodes() instanceof ListNode) {
// multiple conditions for when
for (Node expression : ((ListNode)whenNode.getExpressionNodes()).childNodes()) {
Variable eqqResult = m.getNewTemporaryVariable();
variables.add(eqqResult);
labels.add(bodyLabel);
m.addInstr(new EQQInstr(eqqResult, build(expression, m), value));
m.addInstr(new BEQInstr(eqqResult, BooleanLiteral.TRUE, bodyLabel));
}
} else {
Variable eqqResult = m.getNewTemporaryVariable();
variables.add(eqqResult);
labels.add(bodyLabel);
m.addInstr(new EQQInstr(eqqResult, build(whenNode.getExpressionNodes(), m), value));
m.addInstr(new BEQInstr(eqqResult, BooleanLiteral.TRUE, bodyLabel));
}
// SSS FIXME: This doesn't preserve original order of when clauses. We could consider
// preserving the order (or maybe not, since we would have to sort the constants first
// in any case) for outputing jump tables in certain situations.
//
// add body to map for emitting later
bodies.put(bodyLabel, whenNode.getBodyNode());
}
// Jump to else or the end in case nothing matches!
m.addInstr(new JumpInstr(hasElse ? elseLabel : endLabel));
// build "else" if it exists
if (hasElse) {
caseInstr.setElse(elseLabel);
bodies.put(elseLabel, caseNode.getElseNode());
}
// now emit bodies
for (Map.Entry<Label, Node> entry : bodies.entrySet()) {
m.addInstr(new LABEL_Instr(entry.getKey()));
Operand bodyValue = build(entry.getValue(), m);
// bodyValue can be null if the body ends with a return!
if (bodyValue != null) {
// Local optimization of break results (followed by a copy & jump) to short-circuit the jump right away
// rather than wait to do it during an optimization pass when a dead jump needs to be removed.
Label tgt = endLabel;
if (bodyValue instanceof BreakResult) {
BreakResult br = (BreakResult)bodyValue;
bodyValue = br._result;
tgt = br._jumpTarget;
}