use crate::executor::JITExecutor;
use shape_runtime::engine::{ProgramExecutor, ShapeEngine};
use shape_runtime::initialize_shared_runtime;
use shape_wire::WireValue;
fn jit_eval(source: &str) -> WireValue {
let _ = initialize_shared_runtime();
let mut engine = ShapeEngine::new().expect("engine creation failed");
let program = shape_ast::parse_program(source).expect("parse failed");
let result = JITExecutor::new()
.execute_program(&mut engine, &program)
.expect("JIT execution failed");
result.wire_value
}
fn jit_expect_bool(source: &str, expected: bool) {
match jit_eval(source) {
WireValue::Bool(b) => assert_eq!(b, expected, "Expected bool {}, got {}", expected, b),
other => panic!("Expected Bool({}), got {:?}", expected, other),
}
}
fn jit_expect_int(source: &str, expected: i64) {
match jit_eval(source) {
WireValue::Integer(n) => {
assert_eq!(n, expected, "Expected integer {}, got {}", expected, n)
}
WireValue::Number(n) => {
assert!(
(n - expected as f64).abs() < 1e-9,
"Expected integer {} (got Number {})",
expected,
n
);
}
other => panic!("Expected Integer({}), got {:?}", expected, other),
}
}
#[test]
fn short_circuit_and_value_semantics() {
jit_expect_bool(r#"true && true"#, true);
jit_expect_bool(r#"true && false"#, false);
jit_expect_bool(r#"false && true"#, false);
jit_expect_bool(r#"false && false"#, false);
}
#[test]
fn short_circuit_or_value_semantics() {
jit_expect_bool(r#"true || true"#, true);
jit_expect_bool(r#"true || false"#, true);
jit_expect_bool(r#"false || true"#, true);
jit_expect_bool(r#"false || false"#, false);
}
#[test]
fn or_short_circuits_lhs_true_rhs_divzero_not_evaluated() {
jit_expect_bool(
r#"
fn divzero(x: int) -> bool {
let y = 10 / x
y > 0
}
true || divzero(0)
"#,
true,
);
}
#[test]
fn and_short_circuits_lhs_false_rhs_divzero_not_evaluated() {
jit_expect_bool(
r#"
fn divzero(x: int) -> bool {
let y = 10 / x
y > 0
}
false && divzero(0)
"#,
false,
);
}
#[test]
fn and_no_short_circuit_when_lhs_true_evaluates_rhs() {
jit_expect_bool(
r#"
fn ret_false() -> bool { false }
true && ret_false()
"#,
false,
);
}
#[test]
fn or_no_short_circuit_when_lhs_false_evaluates_rhs() {
jit_expect_bool(
r#"
fn ret_true() -> bool { true }
false || ret_true()
"#,
true,
);
}
#[test]
fn chained_and_short_circuits_at_first_false() {
jit_expect_bool(
r#"
fn divzero(x: int) -> bool {
let y = 10 / x
y > 0
}
true && true && false && divzero(0)
"#,
false,
);
}
#[test]
fn chained_or_short_circuits_at_first_true() {
jit_expect_bool(
r#"
fn divzero(x: int) -> bool {
let y = 10 / x
y > 0
}
false || false || true || divzero(0)
"#,
true,
);
}
#[test]
fn nested_or_short_circuits_inner_and_subexpression() {
jit_expect_bool(
r#"
fn divzero(x: int) -> bool {
let y = 10 / x
y > 0
}
true || (false && divzero(0))
"#,
true,
);
}
#[test]
fn or_short_circuit_does_not_invoke_rhs_function_call() {
jit_expect_int(
r#"
fn main() -> int {
fn always_true() -> bool { true }
let _r = true || always_true()
// Pure value pin: short-circuit means RHS function NOT called.
// (Observed via counter not possible in current JIT mutable-capture
// ABI; pin via value equivalence with raw true literal.)
if true || always_true() { 42 } else { 0 }
}
main()
"#,
42,
);
}