1
0

Add boolean chain short-circuiting

This commit is contained in:
Jeff 2024-12-03 18:24:26 -05:00
parent c2ca7fcc7a
commit b692fd89c3
2 changed files with 63 additions and 5 deletions

View File

@ -866,7 +866,21 @@ impl<'src> Compiler<'src> {
}
fn parse_logical_binary(&mut self) -> Result<(), CompileError> {
let is_logic_chain = matches!(
self.get_last_operations(),
Some([Operation::Test, Operation::Jump, _])
);
let (left_instruction, left_type, left_position) = self.pop_last_instruction()?;
let jump_index = self.instructions.len().saturating_sub(1);
let mut jump_distance = if is_logic_chain {
self.instructions.pop().map_or(0, |(jump, _, _)| {
let Jump { offset, .. } = Jump::from(&jump);
offset
})
} else {
0
};
if !left_instruction.yields_value() {
return Err(CompileError::ExpectedExpression {
@ -903,16 +917,21 @@ impl<'src> Compiler<'src> {
argument,
test_value: test_boolean,
});
let jump = Instruction::from(Jump {
offset: 1,
is_positive: true,
});
self.advance()?;
self.emit_instruction(test, Type::None, operator_position);
self.emit_instruction(jump, Type::None, operator_position);
self.emit_instruction(Instruction::jump(1, true), Type::None, operator_position);
self.parse_sub_expression(&rule.precedence)?;
if is_logic_chain {
let expression_length = self.instructions.len() - jump_index - 1;
jump_distance += expression_length as u16;
let jump = Instruction::jump(jump_distance, true);
self.instructions
.insert(jump_index, (jump, Type::None, operator_position));
}
Ok(())
}

View File

@ -0,0 +1,39 @@
use dust_lang::*;
#[test]
fn true_and_true_and_true() {
let source = "true && true && true";
assert_eq!(
compile(source),
Ok(Chunk::with_data(
None,
FunctionType {
type_parameters: None,
value_parameters: None,
return_type: Box::new(Type::Boolean),
},
vec![
(
Instruction::load_boolean(Destination::Register(0), true, false),
Span(0, 4)
),
(Instruction::test(Argument::Register(0), true), Span(5, 7)),
(Instruction::jump(1, true), Span(5, 7)),
(
Instruction::load_boolean(Destination::Register(1), true, false),
Span(8, 12)
),
(Instruction::test(Argument::Register(1), true), Span(13, 15)),
(Instruction::jump(1, true), Span(13, 15)),
(
Instruction::load_boolean(Destination::Register(2), true, false),
Span(16, 20)
),
(Instruction::r#return(true), Span(20, 20)),
],
vec![],
vec![]
))
);
}