1
//! IF / COND / AND / OR / BEGIN consumed in value position (not just
2
//! effect position). Each is wrapped in arithmetic or comparison so
3
//! `compile_*_for_stack` fires and the value lands on the wasm stack.
4

            
5
use super::common::{compile_and_validate, wrap_with_runtime_ratio};
6

            
7
#[test]
8
1
fn if_for_stack_ratio_result() {
9
    // Both branches return X (runtime Ratio) so the outer `+` sees a
10
    // Ratio. Locks in the `compile_if_for_stack` path for ratio-valued
11
    // IFs.
12
1
    compile_and_validate(&wrap_with_runtime_ratio("(+ (if (= X 0) X X) X)"));
13
1
}
14

            
15
#[test]
16
1
fn if_numeric_literal_branch_coerces_to_ratio() {
17
    // ADR-0028: an integer-literal IF arm coerces to the other arm's numeric
18
    // type (Scalar here) instead of widening to AnyRef. `(if (= X 0) 1 X)` is a
19
    // Ratio IF, so the outer `+ … X` composes. This is the mechanism that lets
20
    // a recursive `(if base 1 (* n (fact …)))` keep a consistent Ratio result.
21
1
    compile_and_validate(&wrap_with_runtime_ratio("(+ (if (= X 0) 1 X) X)"));
22
1
}
23

            
24
#[test]
25
1
fn if_for_stack_no_else_branch() {
26
    // No-else IF in value position; the absent branch defaults to nil
27
    // and the codegen path emits a typed-result block. Consumed as the
28
    // last program form so it lands on the value stack.
29
1
    compile_and_validate(&wrap_with_runtime_ratio("(if (= X 0) (+ X (/ 1 1)))"));
30
1
}
31

            
32
#[test]
33
1
fn runtime_if_with_string_branches_let_bound() {
34
    // A runtime-test IF whose branches are StringRef literals, bound in a
35
    // LET*. The binder sizes its local from the eval-time type, which must
36
    // match the StringRef the codegen actually pushes — previously eval
37
    // collapsed both-literal branches to I32, mis-sizing the local and
38
    // producing an invalid module.
39
1
    compile_and_validate(&wrap_with_runtime_ratio(
40
1
        r#"(let* ((s (if (= X 0) "a" "b"))) s)"#,
41
1
    ));
42
1
}
43

            
44
#[test]
45
1
fn runtime_if_with_ratio_branches_let_bound() {
46
1
    compile_and_validate(&wrap_with_runtime_ratio(
47
1
        "(let* ((r (if (= X 0) 11/10 12/10))) r)",
48
1
    ));
49
1
}
50

            
51
#[test]
52
1
fn cond_runtime_at_effect_position() {
53
    // COND at effect position routes through `compile_cond_for_effect`.
54
    // The cond is a prefix form; the program's last form is X so the
55
    // overall return is Ratio.
56
1
    compile_and_validate(&wrap_with_runtime_ratio(
57
1
        "(cond ((= X 0) (debug \"zero\")) ((> X 0) (debug \"positive\"))) X",
58
1
    ));
59
1
}
60

            
61
#[test]
62
1
fn and_for_stack() {
63
1
    compile_and_validate(&wrap_with_runtime_ratio("(if (and (> X 0) (< X 10)) 1 0)"));
64
1
}
65

            
66
#[test]
67
1
fn or_for_stack() {
68
1
    compile_and_validate(&wrap_with_runtime_ratio("(if (or (= X 0) (= X 1)) 1 0)"));
69
1
}
70

            
71
#[test]
72
1
fn begin_for_stack() {
73
    // `begin` at value position returns the last form's value.
74
1
    compile_and_validate(&wrap_with_runtime_ratio("(+ (begin (debug \"step\") X) 1)"));
75
1
}
76

            
77
#[test]
78
1
fn quote_compiles_for_value_position() {
79
1
    compile_and_validate("'a");
80
1
}
81

            
82
#[test]
83
1
fn quote_constant_list_compiles() {
84
1
    compile_and_validate("'(1 2 3)");
85
1
}