1
//! Built-in registrations: operators, special forms, native fns,
2
//! entity-type/context constants, typed-entity accessors, and the
3
//! MAP-family macros (MAPCAR / MAPC).
4

            
5
use crate::ast::{Expr, Fraction, LambdaParams};
6

            
7
use super::entry::{Symbol, SymbolKind};
8
use super::table::SymbolTable;
9

            
10
impl SymbolTable {
11
85040
    pub fn register_builtins(&mut self) {
12
        // Name lists tangle from doc/scripting/builtin_reference.org
13
        // into builtins_generated.rs — the org registry tables are
14
        // the single source of truth. Adding a builtin = one org row.
15
935440
        for op in super::builtins_generated::OPERATORS {
16
935440
            self.define(Symbol::new(*op, SymbolKind::Operator));
17
935440
        }
18
3741760
        for form in super::builtins_generated::SPECIAL_FORMS {
19
3741760
            self.define(Symbol::new(*form, SymbolKind::SpecialForm));
20
3741760
        }
21
2721280
        for native in super::builtins_generated::NATIVES {
22
2721280
            self.define(Symbol::new(*native, SymbolKind::Native));
23
2721280
        }
24

            
25
85040
        self.register_entity_constants();
26
85040
        self.register_entity_accessors();
27

            
28
85040
        self.add_map_family_macros();
29
85040
    }
30

            
31
85040
    fn register_entity_constants(&mut self) {
32
        use scripting_format::{ContextType, EntityType};
33

            
34
85040
        let entity_types: &[(&str, EntityType)] = &[
35
85040
            ("+ENTITY-TRANSACTION+", EntityType::Transaction),
36
85040
            ("+ENTITY-SPLIT+", EntityType::Split),
37
85040
            ("+ENTITY-TAG+", EntityType::Tag),
38
85040
            ("+ENTITY-ACCOUNT+", EntityType::Account),
39
85040
            ("+ENTITY-COMMODITY+", EntityType::Commodity),
40
85040
        ];
41
425200
        for (name, ty) in entity_types {
42
425200
            self.define(
43
425200
                Symbol::new(*name, SymbolKind::Variable)
44
425200
                    .with_value(Expr::Number(Fraction::from_integer(i64::from(*ty as u8)))),
45
425200
            );
46
425200
        }
47

            
48
85040
        let context_types: &[(&str, ContextType)] = &[
49
85040
            ("+CONTEXT-CREATE+", ContextType::EntityCreate),
50
85040
            ("+CONTEXT-UPDATE+", ContextType::EntityUpdate),
51
85040
            ("+CONTEXT-DELETE+", ContextType::EntityDelete),
52
85040
            ("+CONTEXT-BATCH+", ContextType::BatchProcess),
53
85040
        ];
54
340160
        for (name, ct) in context_types {
55
340160
            self.define(
56
340160
                Symbol::new(*name, SymbolKind::Variable)
57
340160
                    .with_value(Expr::Number(Fraction::from_integer(i64::from(*ct as u8)))),
58
340160
            );
59
340160
        }
60
85040
    }
61

            
62
170080
    pub(super) fn register_entity_accessors(&mut self) {
63
170080
        let accessors = [
64
170080
            "ENTITY-COUNT",
65
170080
            "CONTEXT-TYPE",
66
170080
            "PRIMARY-ENTITY-TYPE",
67
170080
            "PRIMARY-ENTITY-IDX",
68
170080
            "ENTITY-TYPE",
69
170080
            "ENTITY-PARENT-IDX",
70
170080
            "TRANSACTION-SPLIT-COUNT",
71
170080
            "TRANSACTION-TAG-COUNT",
72
170080
            "TRANSACTION-IS-MULTI-CURRENCY",
73
170080
            "TRANSACTION-POST-DATE",
74
170080
            "TRANSACTION-ENTER-DATE",
75
170080
            "SPLIT-VALUE-NUM",
76
170080
            "SPLIT-VALUE-DENOM",
77
170080
            "SPLIT-VALUE",
78
170080
            "SPLIT-RECONCILE-STATE",
79
170080
            "SPLIT-RECONCILE-DATE",
80
170080
            "SPLIT-ACCOUNT-NAME",
81
170080
            "CREATE-TAG",
82
170080
            "TAG-NAME",
83
170080
            "TAG-VALUE",
84
170080
            "STRING=",
85
170080
            "DELETE-ENTITY",
86
170080
            // Typed-entity accessors (mirror `compiler::native::typed_entity`).
87
170080
            "ACCOUNT-ID",
88
170080
            "ACCOUNT-NAME",
89
170080
            "ACCOUNT-PARENT",
90
170080
            "ACCOUNT-TYPE",
91
170080
            "COMMODITY-ID",
92
170080
            "COMMODITY-SYMBOL",
93
170080
            "COMMODITY-NAME",
94
170080
            "TRANSACTION-ID",
95
170080
            "TRANSACTION-NOTE",
96
170080
            "TRANSACTION-AMOUNT",
97
170080
            "SPLIT-ID",
98
170080
            "SPLIT-ACCOUNT-ID",
99
170080
            "SPLIT-COMMODITY-ID",
100
170080
            "SPLIT-AMOUNT",
101
170080
            "TAG-ENTITY-ID",
102
170080
            "TAG-ENTITY-NAME",
103
170080
            "TAG-ENTITY-VALUE",
104
170080
            "PRICE-ID",
105
170080
            "PRICE-COMMODITY-ID",
106
170080
            "PRICE-CURRENCY-ID",
107
170080
            "PRICE-VALUE",
108
170080
            "PRICE-DATE",
109
170080
            "SSH-KEY-ID",
110
170080
            "SSH-KEY-FINGERPRINT",
111
170080
            "SSH-KEY-NAME",
112
170080
            "SSH-KEY-TYPE",
113
170080
            "SSH-KEY-CREATED-AT",
114
170080
            "SSH-KEY-LAST-USED-AT",
115
170080
        ];
116
8504000
        for name in accessors {
117
8504000
            self.define(Symbol::new(name, SymbolKind::Native));
118
8504000
        }
119
170080
    }
120

            
121
85040
    fn add_map_family_macros(&mut self) {
122
85040
        let mapcar_params = LambdaParams {
123
85040
            required: vec!["func".to_string(), "list".to_string()],
124
85040
            optional: Vec::new(),
125
85040
            rest: Some("lists".to_string()),
126
85040
            key: Vec::new(),
127
85040
            aux: Vec::new(),
128
85040
        };
129
85040
        let mapcar_body = Expr::List(vec![
130
85040
            Expr::Symbol("APPLY".to_string()),
131
85040
            Expr::Quote(Box::new(Expr::Symbol("LIST".to_string()))),
132
85040
            Expr::Quote(Box::new(Expr::Symbol("MAP".to_string()))),
133
85040
            Expr::Symbol("func".to_string()),
134
85040
            Expr::Symbol("list".to_string()),
135
85040
            Expr::Symbol("lists".to_string()),
136
85040
        ]);
137
85040
        let mapcar_lambda = Expr::Lambda(mapcar_params, Box::new(mapcar_body));
138
85040
        self.define(Symbol::new("MAPCAR", SymbolKind::Macro).with_function(mapcar_lambda));
139

            
140
85040
        let mapc_params = LambdaParams::simple(vec!["func".to_string(), "list".to_string()]);
141
85040
        let mapc_body = Expr::List(vec![
142
85040
            Expr::Symbol("LIST".to_string()),
143
85040
            Expr::Quote(Box::new(Expr::Symbol("MAP".to_string()))),
144
85040
            Expr::Symbol("func".to_string()),
145
85040
            Expr::Symbol("list".to_string()),
146
85040
        ]);
147
85040
        let mapc_lambda = Expr::Lambda(mapc_params, Box::new(mapc_body));
148
85040
        self.define(Symbol::new("MAPC", SymbolKind::Macro).with_function(mapc_lambda));
149
85040
    }
150
}