1
//! `MAKE-STRUCT-INSTANCE` / `STRUCT-FIELD` / `STRUCT-P` /
2
//! `STRUCT-SET-FIELD` / `MAKE-STRUCT-RUNTIME` natives — the dynamic
3
//! API DEFSTRUCT codegen targets.
4

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

            
7
#[test]
8
1
fn make_struct_instance_string_fields() {
9
1
    compile_and_validate("(make-struct-instance \"Point\" '(x y) '(1 2))");
10
1
}
11

            
12
#[test]
13
1
fn make_struct_instance_wrong_arity_errors() {
14
1
    let err = compile_expect_error("(make-struct-instance)");
15
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
16
1
}
17

            
18
#[test]
19
1
fn make_struct_instance_non_string_name_errors() {
20
1
    let err = compile_expect_error("(make-struct-instance 42 '() '())");
21
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
22
1
}
23

            
24
#[test]
25
1
fn struct_field_lookup_by_name() {
26
1
    compile_and_validate(
27
1
        "(let* ((p (make-struct-instance \"Point\" '(x y) '(1 2)))) \
28
1
           (struct-field p \"x\"))",
29
    );
30
1
}
31

            
32
#[test]
33
1
fn struct_p_returns_bool() {
34
1
    compile_and_validate(
35
1
        "(let* ((p (make-struct-instance \"Point\" '(x) '(1)))) \
36
1
           (struct-p p))",
37
    );
38
1
}
39

            
40
#[test]
41
1
fn struct_p_non_struct_returns_false() {
42
1
    compile_and_validate("(struct-p 42)");
43
1
}
44

            
45
#[test]
46
1
fn make_struct_instance_quoted_string_name() {
47
    // Name as `'"Point"` — quoted-string branch in the name match.
48
1
    compile_and_validate("(make-struct-instance '\"Point\" '(x) '(1))");
49
1
}
50

            
51
#[test]
52
1
fn make_struct_instance_quoted_non_string_name_errors() {
53
1
    let err = compile_expect_error("(make-struct-instance '42 '() '())");
54
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
55
1
}
56

            
57
#[test]
58
1
fn make_struct_instance_non_string_field_errors() {
59
    // Field list element is a number — bad-field-name branch.
60
1
    let err = compile_expect_error("(make-struct-instance \"P\" (list 1) '(1))");
61
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
62
1
}
63

            
64
#[test]
65
1
fn make_struct_instance_quoted_field_with_bad_element_errors() {
66
    // Quoted list of fields, but one element is a number.
67
1
    let err = compile_expect_error("(make-struct-instance \"P\" '(x 42) '(1 2))");
68
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
69
1
}
70

            
71
#[test]
72
1
fn make_struct_instance_non_list_fields_errors() {
73
1
    let err = compile_expect_error("(make-struct-instance \"P\" 42 '(1))");
74
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
75
1
}
76

            
77
#[test]
78
1
fn make_struct_instance_non_list_values_errors() {
79
1
    let err = compile_expect_error("(make-struct-instance \"P\" '(x) 42)");
80
1
    assert!(err.contains("MAKE-STRUCT-INSTANCE"), "got: {err}");
81
1
}
82

            
83
#[test]
84
1
fn make_struct_instance_quoted_values_with_bool_round_trip() {
85
    // Quoted values branch with a Bool element — exercises the
86
    // Expr::Bool arm of the quoted-list value lowering.
87
1
    compile_and_validate("(make-struct-instance \"P\" '(flag) '(t))");
88
1
}
89

            
90
#[test]
91
1
fn make_struct_instance_pads_with_nil_when_short() {
92
    // 2 field names but only 1 value — pads with Nil via the
93
    // `padded_values.push(Value::Nil)` loop.
94
1
    compile_and_validate("(make-struct-instance \"P\" '(x y) '(1))");
95
1
}
96

            
97
#[test]
98
1
fn struct_field_wrong_arity_errors() {
99
1
    let err = compile_expect_error("(struct-field)");
100
1
    assert!(err.contains("STRUCT-FIELD"), "got: {err}");
101
1
}
102

            
103
#[test]
104
1
fn struct_set_field_wrong_arity_errors() {
105
1
    let err = compile_expect_error("(struct-set-field)");
106
1
    assert!(err.contains("STRUCT-SET-FIELD"), "got: {err}");
107
1
}
108

            
109
#[test]
110
1
fn struct_p_wrong_arity_errors() {
111
1
    let err = compile_expect_error("(struct-p)");
112
1
    assert!(err.contains("STRUCT-P"), "got: {err}");
113
1
}
114

            
115
#[test]
116
1
fn struct_set_field_unknown_struct_errors() {
117
    // STRUCT-SET-FIELD requires the struct type to be defined via
118
    // DEFSTRUCT first so the field-name table is registered. Using
119
    // an ad-hoc make-struct-instance triggers an unknown-struct
120
    // error, exercising the lookup-failure path.
121
1
    let err = compile_expect_error(
122
1
        "(let* ((p (make-struct-instance \"Point\" '(x) '(1)))) \
123
1
           (struct-set-field p \"x\" 99))",
124
    );
125
1
    assert!(
126
1
        err.contains("STRUCT-SET-FIELD") || err.contains("Point"),
127
        "got: {err}"
128
    );
129
1
}