1
use crate::ast::{Expr, LambdaParams};
2
use crate::error::{Error, Result};
3
use crate::runtime::{Symbol, SymbolKind, SymbolTable};
4

            
5
use super::super::context::CompileContext;
6
use super::super::emit::FunctionEmitter;
7
use super::super::expr::{compile_expr, eval_value, format_expr};
8

            
9
pub(super) fn compile_defstruct(
10
    ctx: &mut CompileContext,
11
    emit: &mut FunctionEmitter,
12
    symbols: &mut SymbolTable,
13
    args: &[Expr],
14
) -> Result<()> {
15
    let result = defstruct(symbols, args)?;
16
    compile_expr(ctx, emit, symbols, &result)
17
}
18

            
19
pub(super) fn compile_setf(
20
    ctx: &mut CompileContext,
21
    emit: &mut FunctionEmitter,
22
    symbols: &mut SymbolTable,
23
    args: &[Expr],
24
) -> Result<()> {
25
    let result = setf(symbols, args)?;
26
    compile_expr(ctx, emit, symbols, &result)
27
}
28

            
29
73549
pub(super) fn defstruct(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
30
73549
    if args.is_empty() {
31
        return Err(Error::Compile(
32
            "DEFSTRUCT requires a structure name".to_string(),
33
        ));
34
73549
    }
35

            
36
73549
    let name = args[0].as_symbol().ok_or_else(|| {
37
        Error::Compile(format!(
38
            "DEFSTRUCT: expected structure name, got {:?}",
39
            args[0]
40
        ))
41
    })?;
42

            
43
73549
    let fields: Vec<String> = args[1..]
44
73549
        .iter()
45
436806
        .map(|arg| {
46
436806
            arg.as_symbol()
47
436806
                .map(std::string::ToString::to_string)
48
436806
                .ok_or_else(|| {
49
                    Error::Compile(format!("DEFSTRUCT: expected field name, got {arg:?}"))
50
                })
51
436806
        })
52
73549
        .collect::<Result<_>>()?;
53
73549
    symbols.define_struct_fields(name.to_string(), fields.clone());
54

            
55
73549
    let constructor_name = format!("MAKE-{name}");
56
73549
    let constructor_params = LambdaParams {
57
73549
        required: Vec::new(),
58
73549
        optional: Vec::new(),
59
73549
        rest: None,
60
436806
        key: fields.iter().map(|field| (field.clone(), None)).collect(),
61
73549
        aux: Vec::new(),
62
    };
63

            
64
73549
    let constructor_body = {
65
73549
        let field_values: Vec<Expr> = fields
66
73549
            .iter()
67
436806
            .map(|field| Expr::Symbol(field.clone()))
68
73549
            .collect();
69

            
70
73549
        Expr::List(vec![
71
73549
            Expr::Symbol("MAKE-STRUCT-INSTANCE".to_string()),
72
73549
            Expr::Quote(Box::new(Expr::String(name.to_string()))),
73
73549
            Expr::Quote(Box::new(Expr::List(
74
436806
                fields.iter().map(|f| Expr::String(f.clone())).collect(),
75
            ))),
76
73549
            Expr::List(
77
73549
                vec![Expr::Symbol("LIST".to_string())]
78
73549
                    .into_iter()
79
73549
                    .chain(field_values)
80
73549
                    .collect(),
81
73549
            ),
82
        ])
83
    };
84

            
85
73549
    let constructor = Expr::Lambda(constructor_params, Box::new(constructor_body));
86
73549
    symbols.define(
87
73549
        Symbol::new(&constructor_name, SymbolKind::Function).with_function(constructor.clone()),
88
    );
89

            
90
436806
    for field in &fields {
91
436806
        let accessor_name = format!("{name}-{field}");
92
436806
        let accessor_params = LambdaParams::simple(vec!["INSTANCE".to_string()]);
93
436806
        let accessor_body = Expr::List(vec![
94
436806
            Expr::Symbol("STRUCT-FIELD".to_string()),
95
436806
            Expr::Symbol("INSTANCE".to_string()),
96
436806
            Expr::Quote(Box::new(Expr::String(field.clone()))),
97
436806
        ]);
98
436806
        let accessor = Expr::Lambda(accessor_params, Box::new(accessor_body));
99
436806
        symbols.define(Symbol::new(&accessor_name, SymbolKind::Function).with_function(accessor));
100
436806

            
101
436806
        let setf_accessor_name = format!("(SETF {accessor_name})");
102
436806
        let setf_params =
103
436806
            LambdaParams::simple(vec!["INSTANCE".to_string(), "NEW-VALUE".to_string()]);
104
436806
        let setf_body = Expr::List(vec![
105
436806
            Expr::Symbol("STRUCT-SET-FIELD".to_string()),
106
436806
            Expr::Symbol("INSTANCE".to_string()),
107
436806
            Expr::Quote(Box::new(Expr::String(field.clone()))),
108
436806
            Expr::Symbol("NEW-VALUE".to_string()),
109
436806
        ]);
110
436806
        let setf_function = Expr::Lambda(setf_params, Box::new(setf_body));
111
436806
        symbols.define(
112
436806
            Symbol::new(&setf_accessor_name, SymbolKind::Function).with_function(setf_function),
113
436806
        );
114
436806
    }
115

            
116
73549
    let predicate_name = format!("{name}-P");
117
73549
    let predicate_params = LambdaParams::simple(vec!["OBJECT".to_string()]);
118
73549
    let predicate_body = Expr::List(vec![
119
73549
        Expr::Symbol("STRUCT-P".to_string()),
120
73549
        Expr::Symbol("OBJECT".to_string()),
121
73549
        Expr::Quote(Box::new(Expr::String(name.to_string()))),
122
73549
    ]);
123
73549
    let predicate = Expr::Lambda(predicate_params, Box::new(predicate_body));
124
73549
    symbols.define(Symbol::new(&predicate_name, SymbolKind::Function).with_function(predicate));
125

            
126
73549
    Ok(Expr::Quote(Box::new(Expr::Symbol(name.to_string()))))
127
73549
}
128

            
129
44
pub(super) fn setf(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
130
44
    if !args.len().is_multiple_of(2) {
131
        return Err(Error::Compile(
132
            "SETF requires an even number of arguments (place value pairs)".to_string(),
133
        ));
134
44
    }
135

            
136
44
    if args.is_empty() {
137
        return Ok(Expr::Nil);
138
44
    }
139

            
140
44
    let mut last_value = Expr::Nil;
141
44
    for pair in args.chunks(2) {
142
44
        let place = &pair[0];
143
44
        let value = eval_value(symbols, &pair[1])?;
144

            
145
44
        last_value = set_place(symbols, place, value)?;
146
    }
147

            
148
    Ok(last_value)
149
44
}
150

            
151
44
pub(in crate::compiler) fn set_place(
152
44
    symbols: &mut SymbolTable,
153
44
    place: &Expr,
154
44
    value: Expr,
155
44
) -> Result<Expr> {
156
44
    match place {
157
        Expr::Symbol(name) => {
158
            if let Some(sym) = symbols.lookup_mut(name) {
159
                sym.set_value(value.clone());
160
            } else {
161
                symbols.define(Symbol::new(name, SymbolKind::Variable).with_value(value.clone()));
162
            }
163
            Ok(value)
164
        }
165

            
166
44
        Expr::List(exprs) if !exprs.is_empty() => {
167
44
            if let Expr::Symbol(func_name) = &exprs[0] {
168
44
                let setf_name = format!("(SETF {func_name})");
169
44
                if symbols.contains(&setf_name) {
170
44
                    let mut setf_args = exprs[1..].to_vec();
171
44
                    setf_args.push(value.clone());
172
44
                    let call_args: Vec<Expr> = [Expr::Symbol(setf_name)]
173
44
                        .into_iter()
174
44
                        .chain(setf_args)
175
44
                        .collect();
176
44
                    super::super::expr::call(symbols, &call_args)
177
                } else {
178
                    Err(Error::Compile(format!(
179
                        "No setf method defined for accessor '{func_name}'"
180
                    )))
181
                }
182
            } else {
183
                Err(Error::Compile(
184
                    "Invalid place in SETF - expected function call".to_string(),
185
                ))
186
            }
187
        }
188

            
189
        _ => Err(Error::Compile(format!(
190
            "Invalid place in SETF: {}",
191
            format_expr(place)
192
        ))),
193
    }
194
44
}