mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-10 11:44:22 +01:00
Refactor if/ifnot implementation
This commit is contained in:
@@ -749,6 +749,7 @@ fn translate_condition_expr(
|
||||
program.emit_insn(Insn::IfNot {
|
||||
reg,
|
||||
target_pc: target_jump,
|
||||
null_reg: reg,
|
||||
});
|
||||
} else {
|
||||
anyhow::bail!("Parse error: unsupported literal type in condition");
|
||||
@@ -792,6 +793,7 @@ fn translate_condition_expr(
|
||||
Insn::If {
|
||||
reg: cur_reg,
|
||||
target_pc: target_jump,
|
||||
null_reg: cur_reg,
|
||||
},
|
||||
target_jump,
|
||||
)
|
||||
@@ -800,6 +802,7 @@ fn translate_condition_expr(
|
||||
Insn::IfNot {
|
||||
reg: cur_reg,
|
||||
target_pc: target_jump,
|
||||
null_reg: cur_reg,
|
||||
},
|
||||
target_jump,
|
||||
)
|
||||
|
||||
127
core/vdbe.rs
127
core/vdbe.rs
@@ -74,15 +74,19 @@ pub enum Insn {
|
||||
rhs: usize,
|
||||
target_pc: BranchOffset,
|
||||
},
|
||||
// Jump to target_pc if r[reg] is not zero
|
||||
/// Jump to target_pc if r\[reg\] != 0 or (r\[reg\] == NULL && r\[null_reg\] != 0)
|
||||
If {
|
||||
reg: usize,
|
||||
target_pc: BranchOffset,
|
||||
reg: usize, // P1
|
||||
target_pc: BranchOffset, // P2
|
||||
/// P3. If r\[reg\] is null, jump iff r\[null_reg\] != 0
|
||||
null_reg: usize,
|
||||
},
|
||||
// Jump to the given PC if the register is zero.
|
||||
/// Jump to target_pc if r\[reg\] != 0 or (r\[reg\] == NULL && r\[null_reg\] != 0)
|
||||
IfNot {
|
||||
reg: usize,
|
||||
target_pc: BranchOffset,
|
||||
reg: usize, // P1
|
||||
target_pc: BranchOffset, // P2
|
||||
/// P3. If r\[reg\] is null, jump iff r\[null_reg\] != 0
|
||||
null_reg: usize,
|
||||
},
|
||||
// Open a cursor for reading.
|
||||
OpenReadAsync {
|
||||
@@ -417,6 +421,7 @@ impl ProgramBuilder {
|
||||
Insn::If {
|
||||
reg: _reg,
|
||||
target_pc,
|
||||
null_reg,
|
||||
} => {
|
||||
assert!(*target_pc < 0);
|
||||
*target_pc = to_offset;
|
||||
@@ -424,6 +429,7 @@ impl ProgramBuilder {
|
||||
Insn::IfNot {
|
||||
reg: _reg,
|
||||
target_pc,
|
||||
null_reg,
|
||||
} => {
|
||||
assert!(*target_pc < 0);
|
||||
*target_pc = to_offset;
|
||||
@@ -784,30 +790,28 @@ impl Program {
|
||||
}
|
||||
}
|
||||
}
|
||||
Insn::If { reg, target_pc } => {
|
||||
Insn::If {
|
||||
reg,
|
||||
target_pc,
|
||||
null_reg,
|
||||
} => {
|
||||
assert!(*target_pc >= 0);
|
||||
let reg = *reg;
|
||||
let target_pc = *target_pc;
|
||||
match &state.registers[reg] {
|
||||
OwnedValue::Integer(0) => {
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
state.pc = target_pc;
|
||||
}
|
||||
if jump_if(&state.registers[*reg], &state.registers[*null_reg], false) {
|
||||
state.pc = *target_pc;
|
||||
} else {
|
||||
state.pc += 1;
|
||||
}
|
||||
}
|
||||
Insn::IfNot { reg, target_pc } => {
|
||||
Insn::IfNot {
|
||||
reg,
|
||||
target_pc,
|
||||
null_reg,
|
||||
} => {
|
||||
assert!(*target_pc >= 0);
|
||||
let reg = *reg;
|
||||
let target_pc = *target_pc;
|
||||
match &state.registers[reg] {
|
||||
OwnedValue::Integer(0) => {
|
||||
state.pc = target_pc;
|
||||
}
|
||||
_ => {
|
||||
state.pc += 1;
|
||||
}
|
||||
if jump_if(&state.registers[*reg], &state.registers[*null_reg], true) {
|
||||
state.pc = *target_pc;
|
||||
} else {
|
||||
state.pc += 1;
|
||||
}
|
||||
}
|
||||
Insn::OpenReadAsync {
|
||||
@@ -1398,20 +1402,28 @@ fn insn_to_str(program: &Program, addr: InsnReference, insn: &Insn, indent: Stri
|
||||
0,
|
||||
format!("if r[{}]>=r[{}] goto {}", lhs, rhs, target_pc),
|
||||
),
|
||||
Insn::If { reg, target_pc } => (
|
||||
Insn::If {
|
||||
reg,
|
||||
target_pc,
|
||||
null_reg,
|
||||
} => (
|
||||
"If",
|
||||
*reg as i32,
|
||||
*target_pc as i32,
|
||||
0,
|
||||
*null_reg as i32,
|
||||
OwnedValue::Text(Rc::new("".to_string())),
|
||||
0,
|
||||
format!("if r[{}] goto {}", reg, target_pc),
|
||||
),
|
||||
Insn::IfNot { reg, target_pc } => (
|
||||
Insn::IfNot {
|
||||
reg,
|
||||
target_pc,
|
||||
null_reg,
|
||||
} => (
|
||||
"IfNot",
|
||||
*reg as i32,
|
||||
*target_pc as i32,
|
||||
0,
|
||||
*null_reg as i32,
|
||||
OwnedValue::Text(Rc::new("".to_string())),
|
||||
0,
|
||||
format!("if !r[{}] goto {}", reg, target_pc),
|
||||
@@ -1757,3 +1769,58 @@ fn like(pattern: &str, text: &str) -> bool {
|
||||
let re = Regex::new(&format!("{}", pattern.replace("%", ".*").replace("_", "."))).unwrap();
|
||||
re.is_match(text)
|
||||
}
|
||||
|
||||
// step_if returns whether you should jump
|
||||
fn jump_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
||||
match reg {
|
||||
OwnedValue::Integer(0) | OwnedValue::Float(0.0) => not,
|
||||
OwnedValue::Integer(_) | OwnedValue::Float(_) => !not,
|
||||
OwnedValue::Null => match null_reg {
|
||||
OwnedValue::Integer(0) | OwnedValue::Float(0.0) => false,
|
||||
OwnedValue::Integer(_) | OwnedValue::Float(_) => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_like() {
|
||||
assert!(like("a%", "aaaa"));
|
||||
assert!(like("%a%a", "aaaa"));
|
||||
assert!(like("%a.a", "aaaa"));
|
||||
assert!(like("a.a%", "aaaa"));
|
||||
assert!(!like("%a.ab", "aaaa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jump_if() {
|
||||
let reg = OwnedValue::Integer(0);
|
||||
let null_reg = OwnedValue::Integer(0);
|
||||
assert_eq!(jump_if(®, &null_reg, false), false);
|
||||
assert_eq!(jump_if(®, &null_reg, true), true);
|
||||
|
||||
let reg = OwnedValue::Integer(1);
|
||||
let null_reg = OwnedValue::Integer(0);
|
||||
assert_eq!(jump_if(®, &null_reg, false), true);
|
||||
assert_eq!(jump_if(®, &null_reg, true), false);
|
||||
|
||||
let reg = OwnedValue::Null;
|
||||
let null_reg = OwnedValue::Integer(0);
|
||||
assert_eq!(jump_if(®, &null_reg, false), false);
|
||||
assert_eq!(jump_if(®, &null_reg, true), false);
|
||||
|
||||
let reg = OwnedValue::Null;
|
||||
let null_reg = OwnedValue::Integer(1);
|
||||
assert_eq!(jump_if(®, &null_reg, false), true);
|
||||
assert_eq!(jump_if(®, &null_reg, true), true);
|
||||
|
||||
let reg = OwnedValue::Null;
|
||||
let null_reg = OwnedValue::Null;
|
||||
assert_eq!(jump_if(®, &null_reg, false), false);
|
||||
assert_eq!(jump_if(®, &null_reg, true), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,14 @@ accessories|0}
|
||||
|
||||
do_execsql_test where-like {
|
||||
select * from products where name like 'sweat%';
|
||||
} {4|sweater|2.0
|
||||
5|sweatshirt|67.0}
|
||||
} {4|sweater|25.0
|
||||
5|sweatshirt|74.0}
|
||||
|
||||
do_execsql_test where-not-like {
|
||||
select * from products where name not like 'sneak%' and price >= 70.0;
|
||||
} {3|shirt|79.0
|
||||
7|jeans|80.0}
|
||||
select * from products where name not like 'sweat%' and price >= 70.0;
|
||||
} {1|hat|79.0
|
||||
2|cap|82.0
|
||||
6|shorts|70.0
|
||||
7|jeans|78.0
|
||||
8|sneakers|82.0
|
||||
11|accessories|81.0}
|
||||
|
||||
Reference in New Issue
Block a user