Lines
100 %
Functions
60 %
Branches
//! Built-in registrations: operators, special forms, native fns,
//! entity-type/context constants, typed-entity accessors, and the
//! MAP-family macros (MAPCAR / MAPC).
use crate::ast::{Expr, Fraction, LambdaParams};
use super::entry::{Symbol, SymbolKind};
use super::table::SymbolTable;
impl SymbolTable {
pub fn register_builtins(&mut self) {
// Name lists tangle from doc/scripting/builtin_reference.org
// into builtins_generated.rs — the org registry tables are
// the single source of truth. Adding a builtin = one org row.
for op in super::builtins_generated::OPERATORS {
self.define(Symbol::new(*op, SymbolKind::Operator));
}
for form in super::builtins_generated::SPECIAL_FORMS {
self.define(Symbol::new(*form, SymbolKind::SpecialForm));
for native in super::builtins_generated::NATIVES {
self.define(Symbol::new(*native, SymbolKind::Native));
self.register_entity_constants();
self.register_entity_accessors();
self.add_map_family_macros();
fn register_entity_constants(&mut self) {
use scripting_format::{ContextType, EntityType};
let entity_types: &[(&str, EntityType)] = &[
("+ENTITY-TRANSACTION+", EntityType::Transaction),
("+ENTITY-SPLIT+", EntityType::Split),
("+ENTITY-TAG+", EntityType::Tag),
("+ENTITY-ACCOUNT+", EntityType::Account),
("+ENTITY-COMMODITY+", EntityType::Commodity),
];
for (name, ty) in entity_types {
self.define(
Symbol::new(*name, SymbolKind::Variable)
.with_value(Expr::Number(Fraction::from_integer(i64::from(*ty as u8)))),
);
let context_types: &[(&str, ContextType)] = &[
("+CONTEXT-CREATE+", ContextType::EntityCreate),
("+CONTEXT-UPDATE+", ContextType::EntityUpdate),
("+CONTEXT-DELETE+", ContextType::EntityDelete),
("+CONTEXT-BATCH+", ContextType::BatchProcess),
for (name, ct) in context_types {
.with_value(Expr::Number(Fraction::from_integer(i64::from(*ct as u8)))),
pub(super) fn register_entity_accessors(&mut self) {
let accessors = [
"ENTITY-COUNT",
"CONTEXT-TYPE",
"PRIMARY-ENTITY-TYPE",
"PRIMARY-ENTITY-IDX",
"ENTITY-TYPE",
"ENTITY-PARENT-IDX",
"TRANSACTION-SPLIT-COUNT",
"TRANSACTION-TAG-COUNT",
"TRANSACTION-IS-MULTI-CURRENCY",
"TRANSACTION-POST-DATE",
"TRANSACTION-ENTER-DATE",
"SPLIT-VALUE-NUM",
"SPLIT-VALUE-DENOM",
"SPLIT-VALUE",
"SPLIT-RECONCILE-STATE",
"SPLIT-RECONCILE-DATE",
"SPLIT-ACCOUNT-NAME",
"CREATE-TAG",
"TAG-NAME",
"TAG-VALUE",
"STRING=",
"DELETE-ENTITY",
// Typed-entity accessors (mirror `compiler::native::typed_entity`).
"ACCOUNT-ID",
"ACCOUNT-NAME",
"ACCOUNT-PARENT",
"COMMODITY-ID",
"COMMODITY-SYMBOL",
"COMMODITY-NAME",
"TRANSACTION-ID",
"TRANSACTION-NOTE",
"SPLIT-ID",
"SPLIT-ACCOUNT-ID",
"SPLIT-COMMODITY-ID",
"SPLIT-AMOUNT",
"TAG-ENTITY-ID",
"TAG-ENTITY-NAME",
"TAG-ENTITY-VALUE",
"PRICE-ID",
"PRICE-COMMODITY-ID",
"PRICE-CURRENCY-ID",
"PRICE-VALUE",
"PRICE-DATE",
"SSH-KEY-ID",
"SSH-KEY-FINGERPRINT",
"SSH-KEY-NAME",
"NODE-ID",
"NODE-LABEL",
"NODE-DEPTH",
"NODE-AMOUNT",
"NODE-CHILDREN",
for name in accessors {
self.define(Symbol::new(name, SymbolKind::Native));
fn add_map_family_macros(&mut self) {
let mapcar_params = LambdaParams {
required: vec!["func".to_string(), "list".to_string()],
optional: Vec::new(),
rest: Some("lists".to_string()),
key: Vec::new(),
aux: Vec::new(),
};
let mapcar_body = Expr::List(vec![
Expr::Symbol("APPLY".to_string()),
Expr::Quote(Box::new(Expr::Symbol("LIST".to_string()))),
Expr::Quote(Box::new(Expr::Symbol("MAP".to_string()))),
Expr::Symbol("func".to_string()),
Expr::Symbol("list".to_string()),
Expr::Symbol("lists".to_string()),
]);
let mapcar_lambda = Expr::Lambda(mapcar_params, Box::new(mapcar_body));
self.define(Symbol::new("MAPCAR", SymbolKind::Macro).with_function(mapcar_lambda));
let mapc_params = LambdaParams::simple(vec!["func".to_string(), "list".to_string()]);
let mapc_body = Expr::List(vec![
Expr::Symbol("LIST".to_string()),
let mapc_lambda = Expr::Lambda(mapc_params, Box::new(mapc_body));
self.define(Symbol::new("MAPC", SymbolKind::Macro).with_function(mapc_lambda));