1pub mod effects;
2mod lists;
3mod logics;
4mod maps;
5mod math;
6pub mod meta;
7mod records;
8mod refs;
9mod sets;
10mod strings;
11pub mod syntax;
12
13use std::collections::HashMap;
14use std::sync::{Arc, RwLock};
15
16use crate::call_stack::CallStackList;
17use crate::primes::{Calcit, CalcitErr, CalcitItems, CalcitScope, CalcitSyntax};
18
19pub type FnType = fn(xs: &CalcitItems, call_stack: &CallStackList) -> Result<Calcit, CalcitErr>;
20pub type SyntaxType = fn(expr: &CalcitItems, scope: &CalcitScope, file_ns: &str) -> Result<Calcit, CalcitErr>;
21
22lazy_static! {
23 static ref IMPORTED_PROCS: RwLock<HashMap<Arc<str>, FnType>> = RwLock::new(HashMap::new());
24}
25
26pub fn is_proc_name(s: &str) -> bool {
27 let builtin = matches!(
28 s,
29 "type-of"
31 | "recur"
32 | "format-to-lisp"
33 | "format-to-cirru"
34 | "gensym"
35 | "&reset-gensym-index!"
36 | "&get-calcit-running-mode"
37 | "generate-id!"
38 | "turn-symbol"
39 | "turn-keyword"
40 | "&compare"
41 | "&get-os"
42 | "&format-ternary-tree"
43 | "::" | "&tuple:nth"
46 | "&tuple:assoc"
47 | "&display-stack"
49 | "raise"
50 | "quit!"
51 | "get-env"
52 | "&get-calcit-backend"
53 | "read-file"
54 | "write-file"
55 | "parse-cirru"
57 | "format-cirru"
58 | "parse-cirru-edn"
59 | "format-cirru-edn"
60 | "cpu-time"
62 | "&="
64 | "&<"
65 | "&>"
66 | "not"
67 | "identical?"
68 | "&+"
70 | "&-"
71 | "&*"
72 | "&/"
73 | "round"
74 | "floor"
75 | "sin"
76 | "cos"
77 | "pow"
78 | "ceil"
79 | "sqrt"
80 | "round?"
81 | "&number:fract"
82 | "&number:rem"
83 | "&number:format"
84 | "bit-shl"
85 | "bit-shr"
86 | "&str:concat"
88 | "trim"
89 | "&str"
90 | "turn-string"
91 | "split"
92 | "split-lines"
93 | "starts-with?"
94 | "ends-with?"
95 | "get-char-code"
96 | "char-from-code"
97 | "pr-str"
98 | "parse-float"
99 | "blank?"
100 | "&str:compare"
101 | "&str:replace"
102 | "&str:slice"
103 | "&str:find-index"
104 | "&str:escape"
105 | "&str:count"
106 | "&str:empty?"
107 | "&str:contains?"
108 | "&str:includes?"
109 | "&str:nth"
110 | "&str:first"
111 | "&str:rest"
112 | "&str:pad-left"
113 | "&str:pad-right"
114 | "[]"
116 | "'" | "append"
118 | "prepend"
119 | "butlast"
120 | "range"
121 | "sort"
122 | "foldl"
123 | "foldl-shortcut"
124 | "foldr-shortcut"
125 | "&list:reverse"
126 | "&list:concat"
127 | "&list:count"
128 | "&list:empty?"
129 | "&list:slice"
130 | "&list:assoc-before"
131 | "&list:assoc-after"
132 | "&list:contains?"
133 | "&list:includes?"
134 | "&list:nth"
135 | "&list:first"
136 | "&list:rest"
137 | "&list:assoc"
138 | "&list:dissoc"
139 | "&list:to-set"
140 | "&list:distinct"
141 | "&{}"
143 | "&merge"
144 | "to-pairs"
145 | "&merge-non-nil"
146 | "&map:get"
147 | "&map:dissoc"
148 | "&map:to-list"
149 | "&map:count"
150 | "&map:empty?"
151 | "&map:contains?"
152 | "&map:includes?"
153 | "&map:first"
154 | "&map:rest"
155 | "&map:assoc"
156 | "&map:diff-new"
157 | "&map:diff-keys"
158 | "&map:common-keys"
159 | "#{}"
161 | "&include"
162 | "&exclude"
163 | "&difference"
164 | "&union"
165 | "&set:intersection"
166 | "&set:to-list"
167 | "&set:count"
168 | "&set:empty?"
169 | "&set:includes?"
170 | "&set:first"
171 | "&set:rest"
172 | "&set:assoc"
173 | "deref"
175 | "add-watch"
176 | "remove-watch"
177 | "new-record"
179 | "&%{}"
180 | "&record:matches?"
181 | "&record:from-map"
182 | "&record:get-name"
183 | "&record:to-map"
184 | "&record:count"
185 | "&record:contains?"
186 | "&record:get"
187 | "&record:assoc"
188 | "&record:extend-as"
189 );
190 if builtin {
191 true
192 } else {
193 let ps = IMPORTED_PROCS.read().unwrap();
194 ps.contains_key(s)
195 }
196}
197
198pub fn handle_proc(name: &str, args: &CalcitItems, call_stack: &CallStackList) -> Result<Calcit, CalcitErr> {
200 handle_proc_internal(name, args, call_stack).map_err(|e| {
201 if e.stack.is_empty() {
202 let mut e2 = e;
203 e2.stack = call_stack.to_owned();
204 e2
205 } else {
206 e
207 }
208 })
209}
210
211fn handle_proc_internal(name: &str, args: &CalcitItems, call_stack: &CallStackList) -> Result<Calcit, CalcitErr> {
212 match name {
213 "type-of" => meta::type_of(args),
215 "recur" => meta::recur(args),
216 "format-to-lisp" => meta::format_to_lisp(args),
217 "format-to-cirru" => meta::format_to_cirru(args),
218 "gensym" => meta::gensym(args),
219 "&reset-gensym-index!" => meta::reset_gensym_index(args),
220 "&get-calcit-running-mode" => effects::calcit_running_mode(args),
221 "generate-id!" => meta::generate_id(args),
222 "turn-symbol" => meta::turn_symbol(args),
223 "turn-keyword" => meta::turn_keyword(args),
224 "&compare" => meta::native_compare(args),
225 "&get-os" => meta::get_os(args),
226 "&format-ternary-tree" => meta::format_ternary_tree(args),
227 "::" => meta::new_tuple(args), "&tuple:nth" => meta::tuple_nth(args),
230 "&tuple:assoc" => meta::assoc(args),
231 "&display-stack" => meta::display_stack(args, call_stack),
233 "raise" => effects::raise(args),
234 "quit!" => effects::quit(args),
235 "get-env" => effects::get_env(args),
236 "&get-calcit-backend" => effects::call_get_calcit_backend(args),
237 "read-file" => effects::read_file(args),
238 "write-file" => effects::write_file(args),
239 "parse-cirru" => meta::parse_cirru(args),
241 "format-cirru" => meta::format_cirru(args),
242 "parse-cirru-edn" => meta::parse_cirru_edn(args),
243 "format-cirru-edn" => meta::format_cirru_edn(args),
244 "cpu-time" => effects::cpu_time(args),
246 "&=" => logics::binary_equal(args),
248 "&<" => logics::binary_less(args),
249 "&>" => logics::binary_greater(args),
250 "not" => logics::not(args),
251 "identical?" => logics::binary_equal(args),
253 "&+" => math::binary_add(args),
255 "&-" => math::binary_minus(args),
256 "&*" => math::binary_multiply(args),
257 "&/" => math::binary_divide(args),
258 "floor" => math::floor(args),
259 "sin" => math::sin(args),
260 "cos" => math::cos(args),
261 "pow" => math::pow(args),
262 "ceil" => math::ceil(args),
263 "sqrt" => math::sqrt(args),
264 "round" => math::round(args),
265 "round?" => math::round_ques(args),
266 "&number:rem" => math::rem(args),
267 "&number:fract" => math::fractional(args),
268 "&number:format" => strings::format_number(args),
269 "bit-shr" => math::bit_shr(args),
270 "bit-shl" => math::bit_shl(args),
271 "trim" => strings::trim(args),
273 "&str" => strings::call_str(args),
274 "turn-string" => strings::turn_string(args),
275 "split" => strings::split(args),
276 "split-lines" => strings::split_lines(args),
277 "starts-with?" => strings::starts_with_ques(args),
278 "ends-with?" => strings::ends_with_ques(args),
279 "get-char-code" => strings::get_char_code(args),
280 "char-from-code" => strings::char_from_code(args),
281 "parse-float" => strings::parse_float(args),
282 "pr-str" => strings::pr_str(args),
283 "blank?" => strings::blank_ques(args),
284 "&str:concat" => strings::binary_str_concat(args),
285 "&str:slice" => strings::str_slice(args),
286 "&str:compare" => strings::compare_string(args),
287 "&str:find-index" => strings::find_index(args),
288 "&str:replace" => strings::replace(args),
289 "&str:escape" => strings::escape(args),
290 "&str:count" => strings::count(args),
291 "&str:empty?" => strings::empty_ques(args),
292 "&str:contains?" => strings::contains_ques(args),
293 "&str:includes?" => strings::includes_ques(args),
294 "&str:nth" => strings::nth(args),
295 "&str:first" => strings::first(args),
296 "&str:rest" => strings::rest(args),
297 "&str:pad-left" => strings::pad_left(args),
298 "&str:pad-right" => strings::pad_right(args),
299 "[]" => lists::new_list(args),
301 "'" => lists::new_list(args), "append" => lists::append(args),
303 "prepend" => lists::prepend(args),
304 "butlast" => lists::butlast(args),
305 "&list:concat" => lists::concat(args),
306 "range" => lists::range(args),
307 "sort" => lists::sort(args, call_stack),
308 "foldl" => lists::foldl(args, call_stack),
309 "foldl-shortcut" => lists::foldl_shortcut(args, call_stack),
310 "foldr-shortcut" => lists::foldr_shortcut(args, call_stack),
311 "&list:reverse" => lists::reverse(args),
312 "&list:slice" => lists::slice(args),
313 "&list:assoc-before" => lists::assoc_before(args),
314 "&list:assoc-after" => lists::assoc_after(args),
315 "&list:count" => lists::count(args),
316 "&list:empty?" => lists::empty_ques(args),
317 "&list:contains?" => lists::contains_ques(args),
318 "&list:includes?" => lists::includes_ques(args),
319 "&list:nth" => lists::nth(args),
320 "&list:first" => lists::first(args),
321 "&list:rest" => lists::rest(args),
322 "&list:assoc" => lists::assoc(args),
323 "&list:dissoc" => lists::dissoc(args),
324 "&list:to-set" => lists::list_to_set(args),
325 "&list:distinct" => lists::distinct(args),
326 "&{}" => maps::call_new_map(args),
328 "&merge" => maps::call_merge(args),
329 "to-pairs" => maps::to_pairs(args),
330 "&merge-non-nil" => maps::call_merge_non_nil(args),
331 "&map:to-list" => maps::to_list(args),
332 "&map:count" => maps::count(args),
333 "&map:empty?" => maps::empty_ques(args),
334 "&map:contains?" => maps::contains_ques(args),
335 "&map:includes?" => maps::includes_ques(args),
336 "&map:first" => maps::first(args),
337 "&map:rest" => maps::rest(args),
338 "&map:get" => maps::get(args),
339 "&map:assoc" => maps::assoc(args),
340 "&map:dissoc" => maps::dissoc(args),
341 "&map:diff-new" => maps::diff_new(args),
342 "&map:diff-keys" => maps::diff_keys(args),
343 "&map:common-keys" => maps::common_keys(args),
344 "#{}" => sets::new_set(args),
346 "&include" => sets::call_include(args),
347 "&exclude" => sets::call_exclude(args),
348 "&difference" => sets::call_difference(args),
349 "&union" => sets::call_union(args),
350 "&set:intersection" => sets::call_intersection(args),
351 "&set:to-list" => sets::set_to_list(args),
352 "&set:count" => sets::count(args),
353 "&set:empty?" => sets::empty_ques(args),
354 "&set:includes?" => sets::includes_ques(args),
355 "&set:first" => sets::first(args),
356 "&set:rest" => sets::rest(args),
357 "deref" => refs::deref(args),
359 "add-watch" => refs::add_watch(args),
360 "remove-watch" => refs::remove_watch(args),
361 "new-record" => records::new_record(args),
363 "&%{}" => records::call_record(args),
364 "&record:from-map" => records::record_from_map(args),
365 "&record:get-name" => records::get_record_name(args),
366 "&record:to-map" => records::turn_map(args),
367 "&record:matches?" => records::matches(args),
368 "&record:count" => records::count(args),
369 "&record:contains?" => records::contains_ques(args),
370 "&record:get" => records::get(args),
371 "&record:assoc" => records::assoc(args),
372 "&record:extend-as" => records::extend_as(args),
373 a => {
374 let ps = IMPORTED_PROCS.read().unwrap();
375 if ps.contains_key(name) {
376 let f = ps[name];
377 f(args, call_stack)
378 } else {
379 Err(CalcitErr::use_msg_stack(format!("No such proc: {}", a), call_stack))
380 }
381 }
382 }
383}
384
385pub fn register_import_proc(name: &str, f: FnType) {
387 let mut ps = IMPORTED_PROCS.write().unwrap();
388 (*ps).insert(name.to_owned().into(), f);
389}
390
391pub fn handle_syntax(
392 name: &CalcitSyntax,
393 nodes: &CalcitItems,
394 scope: &CalcitScope,
395 file_ns: Arc<str>,
396 call_stack: &CallStackList,
397) -> Result<Calcit, CalcitErr> {
398 match name {
399 CalcitSyntax::Defn => syntax::defn(nodes, scope, file_ns),
400 CalcitSyntax::Eval => syntax::eval(nodes, scope, file_ns, call_stack),
401 CalcitSyntax::Defmacro => syntax::defmacro(nodes, scope, file_ns),
402 CalcitSyntax::Quote => syntax::quote(nodes, scope, file_ns),
403 CalcitSyntax::Quasiquote => syntax::quasiquote(nodes, scope, file_ns, call_stack),
404 CalcitSyntax::If => syntax::syntax_if(nodes, scope, file_ns, call_stack),
405 CalcitSyntax::CoreLet => syntax::syntax_let(nodes, scope, file_ns, call_stack),
406 CalcitSyntax::Macroexpand => syntax::macroexpand(nodes, scope, file_ns, call_stack),
407 CalcitSyntax::Macroexpand1 => syntax::macroexpand_1(nodes, scope, file_ns, call_stack),
408 CalcitSyntax::MacroexpandAll => syntax::macroexpand_all(nodes, scope, file_ns, call_stack),
409 CalcitSyntax::Try => syntax::call_try(nodes, scope, file_ns, call_stack),
410 CalcitSyntax::Defatom => refs::defatom(nodes, scope, file_ns, call_stack),
412 CalcitSyntax::Reset => refs::reset_bang(nodes, scope, file_ns, call_stack),
413 CalcitSyntax::HintFn => meta::no_op(),
415 }
416}
417
418pub fn is_js_syntax_procs(s: &str) -> bool {
421 matches!(
422 s,
423 "aget"
424 | "aset"
425 | "exists?"
426 | "extract-cirru-edn"
427 | "foldl"
428 | "instance?"
429 | "&js-object"
430 | "js-array"
431 | "js-await"
432 | "load-console-formatter!"
433 | "printable"
434 | "new"
435 | "set!"
436 | "timeout-call"
437 | "to-calcit-data"
438 | "to-cirru-edn"
439 | "to-js-data"
440 | "invoke-method" )
442}