nomiscript/runtime/symbol/
stdlib.rs1use crate::ast::{Expr, LambdaParams};
6
7use super::entry::{Symbol, SymbolKind};
8use super::table::SymbolTable;
9
10impl SymbolTable {
11 pub(super) fn load_standard_library(&mut self) {
12 self.load_financial_structs();
13 self.load_essential_macros();
14 }
15
16 fn load_financial_structs(&mut self) {
17 let financial_structs = [
18 (
19 "transaction",
20 vec![
21 "id",
22 "parent-idx",
23 "post-date",
24 "enter-date",
25 "split-count",
26 "tag-count",
27 "is-multi-currency",
28 ],
29 ),
30 (
31 "split",
32 vec![
33 "id",
34 "parent-idx",
35 "account-id",
36 "commodity-id",
37 "value-num",
38 "value-denom",
39 "reconcile-state",
40 "reconcile-date",
41 ],
42 ),
43 ("tag", vec!["id", "parent-idx", "name", "value"]),
44 (
45 "account",
46 vec![
47 "id",
48 "parent-idx",
49 "parent-account-id",
50 "name",
51 "path",
52 "tag-count",
53 ],
54 ),
55 (
56 "commodity",
57 vec!["id", "parent-idx", "symbol", "name", "tag-count"],
58 ),
59 ];
60
61 for (struct_name, field_names) in financial_structs {
62 let mut defstruct_args = vec![Expr::Symbol(struct_name.to_uppercase())];
63 for field_name in field_names {
64 defstruct_args.push(Expr::Symbol(field_name.to_uppercase()));
65 }
66
67 if let Err(e) = crate::compiler::special::call(self, "DEFSTRUCT", &defstruct_args) {
68 tracing::warn!("Failed to load financial struct {}: {:?}", struct_name, e);
69 }
70 }
71 }
72
73 fn load_essential_macros(&mut self) {
74 let when_params = LambdaParams {
75 required: vec!["test".to_string()],
76 optional: Vec::new(),
77 rest: Some("body".to_string()),
78 key: Vec::new(),
79 aux: Vec::new(),
80 };
81 let when_body = Expr::Quasiquote(Box::new(Expr::List(vec![
82 Expr::Symbol("IF".to_string()),
83 Expr::Unquote(Box::new(Expr::Symbol("test".to_string()))),
84 Expr::List(vec![
85 Expr::Symbol("BEGIN".to_string()),
86 Expr::UnquoteSplicing(Box::new(Expr::Symbol("body".to_string()))),
87 ]),
88 Expr::Nil,
89 ])));
90 let when_lambda = Expr::Lambda(when_params, Box::new(when_body));
91 self.define(Symbol::new("WHEN", SymbolKind::Macro).with_function(when_lambda));
92
93 let unless_params = LambdaParams {
94 required: vec!["test".to_string()],
95 optional: Vec::new(),
96 rest: Some("body".to_string()),
97 key: Vec::new(),
98 aux: Vec::new(),
99 };
100 let unless_body = Expr::Quasiquote(Box::new(Expr::List(vec![
101 Expr::Symbol("IF".to_string()),
102 Expr::Unquote(Box::new(Expr::Symbol("test".to_string()))),
103 Expr::Nil,
104 Expr::List(vec![
105 Expr::Symbol("BEGIN".to_string()),
106 Expr::UnquoteSplicing(Box::new(Expr::Symbol("body".to_string()))),
107 ]),
108 ])));
109 let unless_lambda = Expr::Lambda(unless_params, Box::new(unless_body));
110 self.define(Symbol::new("UNLESS", SymbolKind::Macro).with_function(unless_lambda));
111
112 self.add_utility_functions();
113 }
114
115 fn add_utility_functions(&mut self) {
116 let upcase_params = LambdaParams::simple(vec!["string".to_string()]);
117 let upcase_body = Expr::Symbol("UPCASE-STRING".to_string());
118 let upcase_lambda = Expr::Lambda(upcase_params, Box::new(upcase_body));
119 self.define(Symbol::new("UPCASE", SymbolKind::Function).with_function(upcase_lambda));
120 }
121
122 pub(super) fn load_prelude(&mut self) {
130 self.load_nomiscript_defuns(include_str!("prelude.nms"), "universal prelude");
131 }
132
133 pub fn load_nomiscript_defuns(&mut self, source: &str, label: &str) {
140 let program = match crate::reader::Reader::parse(source) {
141 Ok(program) => program,
142 Err(e) => {
143 debug_assert!(false, "{label} failed to parse: {e:?}");
144 tracing::error!("{label} failed to parse: {e:?}");
145 return;
146 }
147 };
148 for form in &program.exprs {
149 match form.as_list().and_then(<[Expr]>::split_first) {
150 Some((Expr::Symbol(head), tail)) if head == "DEFUN" => {
151 if let Err(e) = crate::compiler::special::call(self, "DEFUN", tail) {
152 debug_assert!(false, "{label} defun failed: {e:?}");
153 tracing::error!("{label} defun failed: {e:?}");
154 }
155 }
156 _ => {
157 debug_assert!(false, "{label}: only top-level DEFUN forms are allowed");
158 tracing::error!("{label}: ignored non-DEFUN top-level form");
159 }
160 }
161 }
162 }
163}