1
use std::collections::HashMap;
2

            
3
use crate::ast::Expr;
4

            
5
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6
pub enum SymbolKind {
7
    /// Built-in operators like +, -, *, /
8
    Operator,
9
    /// Native functions implemented in the runtime
10
    Native,
11
    /// User-defined functions
12
    Function,
13
    /// Variables and constants
14
    Variable,
15
    /// Special forms like if, let, define, lambda
16
    SpecialForm,
17
    /// User-defined macros
18
    Macro,
19
}
20

            
21
#[derive(Debug, Clone, PartialEq)]
22
pub struct Symbol {
23
    name: String,
24
    kind: SymbolKind,
25
    value: Option<Expr>,
26
    function: Option<Expr>,
27
    doc: Option<String>,
28
    properties: HashMap<String, Expr>,
29
}
30

            
31
impl Symbol {
32
1077839
    pub fn new(name: impl Into<String>, kind: SymbolKind) -> Self {
33
1077839
        Self {
34
1077839
            name: name.into(),
35
1077839
            kind,
36
1077839
            value: None,
37
1077839
            function: None,
38
1077839
            doc: None,
39
1077839
            properties: HashMap::new(),
40
1077839
        }
41
1077839
    }
42

            
43
    #[must_use]
44
12650
    pub fn with_value(mut self, value: Expr) -> Self {
45
12650
        self.value = Some(value);
46
12650
        self
47
12650
    }
48

            
49
    #[must_use]
50
35
    pub fn name(&self) -> &str {
51
35
        &self.name
52
35
    }
53

            
54
    #[must_use]
55
45196
    pub fn kind(&self) -> SymbolKind {
56
45196
        self.kind
57
45196
    }
58

            
59
    #[must_use]
60
9456
    pub fn value(&self) -> Option<&Expr> {
61
9456
        self.value.as_ref()
62
9456
    }
63

            
64
986
    pub fn set_value(&mut self, value: Expr) {
65
986
        self.value = Some(value);
66
986
    }
67

            
68
    #[must_use]
69
492453
    pub fn with_function(mut self, func: Expr) -> Self {
70
492453
        self.function = Some(func);
71
492453
        self
72
492453
    }
73

            
74
    #[must_use]
75
45090
    pub fn function(&self) -> Option<&Expr> {
76
45090
        self.function.as_ref()
77
45090
    }
78

            
79
    pub fn set_function(&mut self, func: Expr) {
80
        self.function = Some(func);
81
    }
82

            
83
    #[must_use]
84
103
    pub fn with_doc(mut self, doc: impl Into<String>) -> Self {
85
103
        self.doc = Some(doc.into());
86
103
        self
87
103
    }
88

            
89
    #[must_use]
90
104
    pub fn doc(&self) -> Option<&str> {
91
104
        self.doc.as_deref()
92
104
    }
93

            
94
    pub fn set_doc(&mut self, doc: impl Into<String>) {
95
        self.doc = Some(doc.into());
96
    }
97

            
98
    #[must_use]
99
3
    pub fn get_property(&self, key: &str) -> Option<&Expr> {
100
3
        self.properties.get(key)
101
3
    }
102

            
103
2
    pub fn set_property(&mut self, key: impl Into<String>, value: Expr) {
104
2
        self.properties.insert(key.into(), value);
105
2
    }
106

            
107
    pub fn remove_property(&mut self, key: &str) -> Option<Expr> {
108
        self.properties.remove(key)
109
    }
110

            
111
    #[must_use]
112
    pub fn properties(&self) -> &HashMap<String, Expr> {
113
        &self.properties
114
    }
115
}
116

            
117
#[derive(Debug, Clone, Default)]
118
pub struct SymbolTable {
119
    symbols: HashMap<String, Symbol>,
120
    struct_fields: HashMap<String, Vec<String>>,
121
}
122

            
123
impl SymbolTable {
124
    #[must_use]
125
8783
    pub fn new() -> Self {
126
8783
        Self::default()
127
8783
    }
128

            
129
    #[must_use]
130
8299
    pub fn with_builtins() -> Self {
131
8299
        let mut table = Self::new();
132
8299
        table.register_builtins();
133
8299
        table.load_standard_library();
134
8299
        table
135
8299
    }
136

            
137
    #[must_use]
138
    pub fn with_builtins_for_wasm() -> Self {
139
        let mut table = Self::new();
140
        table.register_builtins();
141
        // Skip loading standard library to avoid runtime values that can't be compiled to WASM
142
        // The essential macros and financial structs will be defined inline in scripts
143
        table
144
    }
145

            
146
8299
    pub fn register_builtins(&mut self) {
147
8299
        let operators = ["+", "-", "*", "/", "=", "/=", "<", ">", "<=", ">=", "MOD"];
148
91289
        for op in operators {
149
91289
            self.define(Symbol::new(op, SymbolKind::Operator));
150
91289
        }
151

            
152
8299
        let special_forms = [
153
8299
            "IF",
154
8299
            "COND",
155
8299
            "LET",
156
8299
            "LET*",
157
8299
            "LETREC",
158
8299
            "DEFINE",
159
8299
            "DEFUN",
160
8299
            "DEFVAR",
161
8299
            "DEFPARAMETER",
162
8299
            "LAMBDA",
163
8299
            "QUOTE",
164
8299
            "FUNCTION",
165
8299
            "SET!",
166
8299
            "SETF",
167
8299
            "BEGIN",
168
8299
            "AND",
169
8299
            "OR",
170
8299
            "APPLY",
171
8299
            "FUNCALL",
172
8299
            "COMPILE",
173
8299
            "EVAL",
174
8299
            "DESCRIBE",
175
8299
            "DO",
176
8299
            "DO*",
177
8299
            "DEFMACRO",
178
8299
            "MACROEXPAND-1",
179
8299
            "MACROEXPAND",
180
8299
            "LABELS",
181
8299
            "DOLIST",
182
8299
            "DEFSTRUCT",
183
8299
        ];
184
248970
        for form in special_forms {
185
248970
            self.define(Symbol::new(form, SymbolKind::SpecialForm));
186
248970
        }
187

            
188
8299
        let natives = [
189
8299
            "CAR",
190
8299
            "CDR",
191
8299
            "CONS",
192
8299
            "LIST",
193
8299
            "NULL?",
194
8299
            "PAIR?",
195
8299
            "EQ?",
196
8299
            "EQUAL?",
197
8299
            "NOT",
198
8299
            "PRINT",
199
8299
            "DISPLAY",
200
8299
            "NEWLINE",
201
8299
            "LENGTH",
202
8299
            "APPEND",
203
8299
            "REVERSE",
204
8299
            "MAP",
205
8299
            "FILTER",
206
8299
            "FOLD",
207
8299
            "DEBUG",
208
8299
            "EQL",
209
8299
            "EQUAL",
210
8299
            "MAKE-STRUCT-INSTANCE",
211
8299
            "STRUCT-FIELD",
212
8299
            "STRUCT-P",
213
8299
            "STRUCT-SET-FIELD",
214
8299
            "UPCASE-STRING",
215
8299
            "GET-INPUT-ENTITIES",
216
8299
            "MAKE-STRUCT-RUNTIME",
217
8299
        ];
218
232372
        for native in natives {
219
232372
            self.define(Symbol::new(native, SymbolKind::Native));
220
232372
        }
221

            
222
        // Add MAP* family macros
223
8299
        self.add_map_family_macros();
224
8299
    }
225

            
226
8299
    fn add_map_family_macros(&mut self) {
227
        use crate::ast::{Expr, LambdaParams};
228

            
229
        // MAPCAR - alias to MAP, supports one or more list arguments
230
8299
        let mapcar_params = LambdaParams {
231
8299
            required: vec!["func".to_string(), "list".to_string()],
232
8299
            optional: Vec::new(),
233
8299
            rest: Some("lists".to_string()),
234
8299
            key: Vec::new(),
235
8299
            aux: Vec::new(),
236
8299
        };
237
8299
        let mapcar_body = Expr::List(vec![
238
8299
            Expr::Symbol("APPLY".to_string()),
239
8299
            Expr::Quote(Box::new(Expr::Symbol("LIST".to_string()))),
240
8299
            Expr::Quote(Box::new(Expr::Symbol("MAP".to_string()))),
241
8299
            Expr::Symbol("func".to_string()),
242
8299
            Expr::Symbol("list".to_string()),
243
8299
            Expr::Symbol("lists".to_string()),
244
8299
        ]);
245
8299
        let mapcar_lambda = Expr::Lambda(mapcar_params, Box::new(mapcar_body));
246
8299
        self.define(Symbol::new("MAPCAR", SymbolKind::Macro).with_function(mapcar_lambda));
247

            
248
        // MAPC - apply function for side effects, return the original list
249
8299
        let mapc_params = LambdaParams::simple(vec!["func".to_string(), "list".to_string()]);
250
8299
        let mapc_body = Expr::List(vec![
251
8299
            Expr::Symbol("LIST".to_string()),
252
8299
            Expr::Quote(Box::new(Expr::Symbol("MAP".to_string()))),
253
8299
            Expr::Symbol("func".to_string()),
254
8299
            Expr::Symbol("list".to_string()),
255
8299
        ]);
256
8299
        let mapc_lambda = Expr::Lambda(mapc_params, Box::new(mapc_body));
257
8299
        self.define(Symbol::new("MAPC", SymbolKind::Macro).with_function(mapc_lambda));
258
8299
    }
259

            
260
8299
    fn load_standard_library(&mut self) {
261
        // Load financial domain structs automatically
262
8299
        self.load_financial_structs();
263

            
264
        // Load essential Common Lisp macros
265
8299
        self.load_essential_macros();
266
8299
    }
267

            
268
8299
    fn load_financial_structs(&mut self) {
269
        // Define financial domain structs that match the binary format
270
8299
        let financial_structs = [
271
8299
            (
272
8299
                "transaction",
273
8299
                vec![
274
8299
                    "post-date",
275
8299
                    "enter-date",
276
8299
                    "split-count",
277
8299
                    "tag-count",
278
8299
                    "is-multi-currency",
279
8299
                ],
280
8299
            ),
281
8299
            (
282
8299
                "split",
283
8299
                vec![
284
8299
                    "account-id",
285
8299
                    "commodity-id",
286
8299
                    "value-num",
287
8299
                    "value-denom",
288
8299
                    "reconcile-state",
289
8299
                    "reconcile-date",
290
8299
                ],
291
8299
            ),
292
8299
            ("tag", vec!["name", "value"]),
293
8299
            (
294
8299
                "account",
295
8299
                vec!["parent-account-id", "name", "path", "tag-count"],
296
8299
            ),
297
8299
            ("commodity", vec!["symbol", "name", "tag-count"]),
298
8299
        ];
299

            
300
        // Use the special forms compiler to define each struct
301
41495
        for (struct_name, field_names) in financial_structs {
302
41495
            let mut defstruct_args = vec![Expr::Symbol(struct_name.to_uppercase())];
303
165980
            for field_name in field_names {
304
165980
                defstruct_args.push(Expr::Symbol(field_name.to_uppercase()));
305
165980
            }
306

            
307
            // Call defstruct to define the struct and its accessors
308
41495
            if let Err(e) = crate::compiler::special::call(self, "DEFSTRUCT", &defstruct_args) {
309
                tracing::warn!("Failed to load financial struct {}: {:?}", struct_name, e);
310
41495
            }
311
        }
312
8299
    }
313

            
314
8299
    fn load_essential_macros(&mut self) {
315
        use crate::ast::{Expr, LambdaParams};
316

            
317
        // WHEN macro: (when test body...)
318
8299
        let when_params = LambdaParams {
319
8299
            required: vec!["test".to_string()],
320
8299
            optional: Vec::new(),
321
8299
            rest: Some("body".to_string()),
322
8299
            key: Vec::new(),
323
8299
            aux: Vec::new(),
324
8299
        };
325
8299
        let when_body = Expr::Quasiquote(Box::new(Expr::List(vec![
326
8299
            Expr::Symbol("IF".to_string()),
327
8299
            Expr::Unquote(Box::new(Expr::Symbol("test".to_string()))),
328
8299
            Expr::List(vec![
329
8299
                Expr::Symbol("BEGIN".to_string()),
330
8299
                Expr::UnquoteSplicing(Box::new(Expr::Symbol("body".to_string()))),
331
8299
            ]),
332
8299
            Expr::Nil,
333
8299
        ])));
334
8299
        let when_lambda = Expr::Lambda(when_params, Box::new(when_body));
335
8299
        self.define(Symbol::new("WHEN", SymbolKind::Macro).with_function(when_lambda));
336

            
337
        // UNLESS macro: (unless test body...)
338
8299
        let unless_params = LambdaParams {
339
8299
            required: vec!["test".to_string()],
340
8299
            optional: Vec::new(),
341
8299
            rest: Some("body".to_string()),
342
8299
            key: Vec::new(),
343
8299
            aux: Vec::new(),
344
8299
        };
345
8299
        let unless_body = Expr::Quasiquote(Box::new(Expr::List(vec![
346
8299
            Expr::Symbol("IF".to_string()),
347
8299
            Expr::Unquote(Box::new(Expr::Symbol("test".to_string()))),
348
8299
            Expr::Nil,
349
8299
            Expr::List(vec![
350
8299
                Expr::Symbol("BEGIN".to_string()),
351
8299
                Expr::UnquoteSplicing(Box::new(Expr::Symbol("body".to_string()))),
352
8299
            ]),
353
8299
        ])));
354
8299
        let unless_lambda = Expr::Lambda(unless_params, Box::new(unless_body));
355
8299
        self.define(Symbol::new("UNLESS", SymbolKind::Macro).with_function(unless_lambda));
356

            
357
        // Add more essential utility functions
358
8299
        self.add_utility_functions();
359
8299
    }
360

            
361
8299
    fn add_utility_functions(&mut self) {
362
        use crate::ast::{Expr, LambdaParams};
363

            
364
        // UPCASE function (for string manipulation)
365
8299
        let upcase_params = LambdaParams::simple(vec!["string".to_string()]);
366
8299
        let upcase_body = Expr::Symbol("UPCASE-STRING".to_string()); // Will be implemented as native
367
8299
        let upcase_lambda = Expr::Lambda(upcase_params, Box::new(upcase_body));
368
8299
        self.define(Symbol::new("UPCASE", SymbolKind::Function).with_function(upcase_lambda));
369
8299
    }
370

            
371
1077802
    pub fn define(&mut self, symbol: Symbol) {
372
1077802
        self.symbols.insert(symbol.name.clone(), symbol);
373
1077802
    }
374

            
375
    #[must_use]
376
45606
    pub fn lookup(&self, name: &str) -> Option<&Symbol> {
377
45606
        self.symbols.get(name)
378
45606
    }
379

            
380
2994
    pub fn lookup_mut(&mut self, name: &str) -> Option<&mut Symbol> {
381
2994
        self.symbols.get_mut(name)
382
2994
    }
383

            
384
170
    pub fn remove(&mut self, name: &str) -> Option<Symbol> {
385
170
        self.symbols.remove(name)
386
170
    }
387

            
388
    #[must_use]
389
245
    pub fn contains(&self, name: &str) -> bool {
390
245
        self.symbols.contains_key(name)
391
245
    }
392

            
393
    pub fn iter(&self) -> impl Iterator<Item = (&String, &Symbol)> {
394
        self.symbols.iter()
395
    }
396

            
397
43569
    pub fn define_struct_fields(&mut self, name: impl Into<String>, fields: Vec<String>) {
398
43569
        self.struct_fields.insert(name.into(), fields);
399
43569
    }
400

            
401
    #[must_use]
402
170
    pub fn struct_fields(&self, name: &str) -> Option<&[String]> {
403
170
        self.struct_fields.get(name).map(Vec::as_slice)
404
170
    }
405
}
406

            
407
#[cfg(test)]
408
mod tests {
409
    use super::*;
410

            
411
    #[test]
412
1
    fn test_symbol_creation() {
413
1
        let sym = Symbol::new("foo", SymbolKind::Variable);
414
1
        assert_eq!(sym.name(), "foo");
415
1
        assert_eq!(sym.kind(), SymbolKind::Variable);
416
1
        assert!(sym.value().is_none());
417
1
    }
418

            
419
    #[test]
420
1
    fn test_symbol_with_value() {
421
1
        let sym = Symbol::new("x", SymbolKind::Variable).with_value(Expr::Bool(true));
422
1
        assert!(sym.value().is_some());
423
1
        assert_eq!(sym.value(), Some(&Expr::Bool(true)));
424
1
    }
425

            
426
    #[test]
427
1
    fn test_symbol_properties() {
428
1
        let mut sym = Symbol::new("test", SymbolKind::Function);
429
1
        sym.set_property("doc", Expr::String("A test function".into()));
430
1
        sym.set_property("pure", Expr::Bool(true));
431

            
432
1
        assert_eq!(
433
1
            sym.get_property("doc"),
434
1
            Some(&Expr::String("A test function".into()))
435
        );
436
1
        assert_eq!(sym.get_property("pure"), Some(&Expr::Bool(true)));
437
1
        assert!(sym.get_property("nonexistent").is_none());
438
1
    }
439

            
440
    #[test]
441
1
    fn test_symbol_table_builtins() {
442
1
        let table = SymbolTable::with_builtins();
443

            
444
1
        assert!(table.contains("+"));
445
1
        assert_eq!(table.lookup("+").unwrap().kind(), SymbolKind::Operator);
446

            
447
1
        assert!(table.contains("IF"));
448
1
        assert_eq!(table.lookup("IF").unwrap().kind(), SymbolKind::SpecialForm);
449

            
450
1
        assert!(table.contains("CAR"));
451
1
        assert_eq!(table.lookup("CAR").unwrap().kind(), SymbolKind::Native);
452

            
453
1
        assert!(table.contains("EVAL"));
454
1
        assert_eq!(
455
1
            table.lookup("EVAL").unwrap().kind(),
456
            SymbolKind::SpecialForm
457
        );
458

            
459
1
        assert!(table.contains("DEBUG"));
460
1
        assert_eq!(table.lookup("DEBUG").unwrap().kind(), SymbolKind::Native);
461
1
    }
462

            
463
    #[test]
464
1
    fn test_symbol_table_define_lookup() {
465
1
        let mut table = SymbolTable::new();
466
1
        table.define(Symbol::new("my-func", SymbolKind::Function));
467

            
468
1
        assert!(table.contains("my-func"));
469
1
        assert!(!table.contains("undefined"));
470

            
471
1
        let sym = table.lookup("my-func").unwrap();
472
1
        assert_eq!(sym.kind(), SymbolKind::Function);
473
1
    }
474
}