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}