1use crate::{
2 builtins::{is_js_syntax_procs, is_proc_name},
3 call_stack::{extend_call_stack, CalcitStack, CallStackList, StackKind},
4 primes,
5 primes::{Calcit, CalcitErr, CalcitItems, CalcitSyntax, ImportRule, SymbolResolved::*},
6 program, runner,
7};
8
9use std::cell::RefCell;
10use std::collections::HashSet;
11use std::sync::Arc;
12
13use im_ternary_tree::TernaryTreeList;
14
15fn pick_macro_fn(x: Calcit) -> Option<Calcit> {
18 match &x {
19 Calcit::Fn { .. } | Calcit::Macro { .. } => Some(x),
20 _ => None,
21 }
22}
23
24pub fn preprocess_ns_def(
27 raw_ns: Arc<str>,
28 raw_def: Arc<str>,
29 raw_sym: Arc<str>,
31 import_rule: Option<Arc<ImportRule>>, check_warnings: &RefCell<Vec<String>>,
33 call_stack: &rpds::ListSync<CalcitStack>,
34) -> Result<(Calcit, Option<Calcit>), CalcitErr> {
35 let ns = &raw_ns;
36 let def = &raw_def;
37 let original_sym = &raw_sym;
38 match program::lookup_evaled_def(ns, def) {
40 Some(v) => {
41 Ok((
43 Calcit::Symbol {
44 sym: original_sym.to_owned(),
45 ns: ns.to_owned(),
46 at_def: def.to_owned(),
47 resolved: Some(Arc::new(ResolvedDef {
48 ns: ns.to_owned(),
49 def: def.to_owned(),
50 rule: import_rule,
51 })),
52 },
53 pick_macro_fn(v),
54 ))
55 }
56 None => {
57 match program::lookup_def_code(ns, def) {
59 Some(code) => {
60 program::write_evaled_def(ns, def, Calcit::Nil).map_err(|e| CalcitErr::use_msg_stack(e, call_stack))?;
62
63 let next_stack = extend_call_stack(
64 call_stack,
65 ns.to_owned(),
66 def.to_owned(),
67 StackKind::Fn,
68 code.to_owned(),
69 &TernaryTreeList::Empty,
70 );
71
72 let (resolved_code, _resolve_value) = preprocess_expr(&code, &HashSet::new(), ns.to_owned(), check_warnings, &next_stack)?;
73 let v = if is_fn_or_macro(&resolved_code) {
75 match runner::evaluate_expr(&resolved_code, &rpds::HashTrieMap::new_sync(), ns.to_owned(), &next_stack) {
76 Ok(ret) => ret,
77 Err(e) => return Err(e),
78 }
79 } else {
80 Calcit::Thunk(Arc::new(resolved_code), None)
81 };
82 program::write_evaled_def(ns, def, v.to_owned()).map_err(|e| CalcitErr::use_msg_stack(e, call_stack))?;
84
85 Ok((
86 Calcit::Symbol {
87 sym: original_sym.to_owned(),
88 ns: ns.to_owned(),
89 at_def: def.to_owned(),
90 resolved: Some(Arc::new(ResolvedDef {
91 ns: ns.to_owned(),
92 def: def.to_owned(),
93 rule: Some(Arc::new(ImportRule::NsReferDef(ns.to_owned(), def.to_owned()))),
94 })),
95 },
96 pick_macro_fn(v),
97 ))
98 }
99 None if ns.starts_with('|') || ns.starts_with('"') => Ok((
100 Calcit::Symbol {
101 sym: original_sym.to_owned(),
102 ns: ns.to_owned(),
103 at_def: def.to_owned(),
104 resolved: Some(Arc::new(ResolvedDef {
105 ns: ns.to_owned(),
106 def: def.to_owned(),
107 rule: import_rule,
108 })),
109 },
110 None,
111 )),
112 None => Err(CalcitErr::use_msg_stack(
113 format!("unknown ns/def in program: {}/{}", ns, def),
114 call_stack,
115 )),
116 }
117 }
118 }
119}
120
121fn is_fn_or_macro(code: &Calcit) -> bool {
122 match code {
123 Calcit::List(xs) => match xs.get(0) {
124 Some(Calcit::Symbol { sym, .. }) => &**sym == "defn" || &**sym == "defmacro",
125 Some(Calcit::Syntax(s, ..)) => s == &CalcitSyntax::Defn || s == &CalcitSyntax::Defmacro,
126 _ => false,
127 },
128 _ => false,
129 }
130}
131
132pub fn preprocess_expr(
133 expr: &Calcit,
134 scope_defs: &HashSet<Arc<str>>,
135 file_ns: Arc<str>,
136 check_warnings: &RefCell<Vec<String>>,
137 call_stack: &CallStackList,
138) -> Result<(Calcit, Option<Calcit>), CalcitErr> {
139 match expr {
141 Calcit::Symbol {
142 sym: def,
143 ns: def_ns,
144 at_def,
145 ..
146 } => match runner::parse_ns_def(def) {
147 Some((ns_alias, def_part)) => {
148 if &*ns_alias == "js" {
149 Ok((
150 Calcit::Symbol {
151 sym: def.to_owned(),
152 ns: def_ns.to_owned(),
153 at_def: at_def.to_owned(),
154 resolved: Some(Arc::new(ResolvedDef {
155 ns: String::from("js").into(),
156 def: (*def_part).into(),
157 rule: None,
158 })),
159 },
160 None,
161 ))
162 } else if let Some(target_ns) = program::lookup_ns_target_in_import(def_ns.to_owned(), &ns_alias) {
163 preprocess_ns_def(target_ns, def_part, def.to_owned(), None, check_warnings, call_stack)
165 } else if program::has_def_code(&ns_alias, &def_part) {
166 preprocess_ns_def(ns_alias.to_owned(), def_part, def.to_owned(), None, check_warnings, call_stack)
168 } else {
169 Err(CalcitErr::use_msg_stack(format!("unknown ns target: {}", def), call_stack))
170 }
171 }
172 None => {
173 let def_ref = &**def;
174 if def_ref == "~" || def_ref == "~@" || def_ref == "&" || def_ref == "?" {
175 Ok((
176 Calcit::Symbol {
177 sym: def.to_owned(),
178 ns: def_ns.to_owned(),
179 at_def: at_def.to_owned(),
180 resolved: Some(Arc::new(ResolvedRaw)),
181 },
182 None,
183 ))
184 } else if scope_defs.contains(def) {
185 Ok((
186 Calcit::Symbol {
187 sym: def.to_owned(),
188 ns: def_ns.to_owned(),
189 at_def: at_def.to_owned(),
190 resolved: Some(Arc::new(ResolvedLocal)),
191 },
192 None,
193 ))
194 } else if CalcitSyntax::is_core_syntax(def) {
195 Ok((
196 Calcit::Syntax(
197 CalcitSyntax::from(def).map_err(|e| CalcitErr::use_msg_stack(e, call_stack))?,
198 def_ns.to_owned(),
199 ),
200 None,
201 ))
202 } else if is_proc_name(def) {
203 Ok((Calcit::Proc(def.to_owned()), None))
204 } else if program::has_def_code(primes::CORE_NS, def) {
205 preprocess_ns_def(
206 primes::CORE_NS.into(),
207 def.to_owned(),
208 def.to_owned(),
209 None,
210 check_warnings,
211 call_stack,
212 )
213 } else if program::has_def_code(def_ns, def) {
214 preprocess_ns_def(def_ns.to_owned(), def.to_owned(), def.to_owned(), None, check_warnings, call_stack)
215 } else {
216 match program::lookup_def_target_in_import(def_ns, def) {
217 Some(target_ns) => {
218 preprocess_ns_def(target_ns, def.to_owned(), def.to_owned(), None, check_warnings, call_stack)
221 }
222 None if is_js_syntax_procs(def) => Ok((expr.to_owned(), None)),
224 None if def.starts_with('.') => Ok((expr.to_owned(), None)),
225 None => {
226 let from_default = program::lookup_default_target_in_import(def_ns, def);
227 if let Some(target_ns) = from_default {
228 let target = Some(Arc::new(ResolvedDef {
229 ns: target_ns.to_owned(),
230 def: def.to_owned(),
231 rule: Some(Arc::new(ImportRule::NsDefault(target_ns))),
232 }));
233 Ok((
234 Calcit::Symbol {
235 sym: def.to_owned(),
236 ns: def_ns.to_owned(),
237 at_def: at_def.to_owned(),
238 resolved: target,
239 },
240 None,
241 ))
242 } else {
243 let mut names: Vec<Arc<str>> = Vec::with_capacity(scope_defs.len());
244 for def in scope_defs {
245 names.push(def.to_owned());
246 }
247 let mut warnings = check_warnings.borrow_mut();
248 warnings.push(format!(
249 "[Warn] unknown `{}` in {}/{}, locals {{{}}}",
250 def,
251 def_ns,
252 at_def,
253 names.join(" ")
254 ));
255 Ok((expr.to_owned(), None))
256 }
257 }
258 }
259 }
260 }
261 },
262 Calcit::List(xs) => {
263 if xs.is_empty() {
264 Ok((expr.to_owned(), None))
265 } else {
266 process_list_call(xs, scope_defs, file_ns, check_warnings, call_stack)
269 }
270 }
271 Calcit::Number(..) | Calcit::Str(..) | Calcit::Nil | Calcit::Bool(..) | Calcit::Keyword(..) => Ok((expr.to_owned(), None)),
272 Calcit::Proc(..) => {
273 Ok((expr.to_owned(), None))
275 }
276
277 _ => {
278 let mut warnings = check_warnings.borrow_mut();
279 warnings.push(format!("[Warn] unexpected data during preprocess: {:?}", expr));
280 Ok((expr.to_owned(), None))
281 }
282 }
283}
284
285fn process_list_call(
286 xs: &CalcitItems,
287 scope_defs: &HashSet<Arc<str>>,
288 file_ns: Arc<str>,
289 check_warnings: &RefCell<Vec<String>>,
290 call_stack: &CallStackList,
291) -> Result<(Calcit, Option<Calcit>), CalcitErr> {
292 let head = &xs[0];
293 let (head_form, head_evaled) = preprocess_expr(head, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?;
294 let args = xs.drop_left();
295 let def_name = grab_def_name(head);
296
297 match (&head_form, &head_evaled) {
315 (Calcit::Keyword(..), _) => {
316 if args.len() == 1 {
317 let code = Calcit::List(TernaryTreeList::from(&[
318 Calcit::Symbol {
319 sym: String::from("get").into(),
320 ns: String::from(primes::CORE_NS).into(),
321 at_def: String::from(primes::GENERATED_DEF).into(),
322 resolved: Some(Arc::new(ResolvedDef {
323 ns: String::from(primes::CORE_NS).into(),
324 def: String::from("get").into(),
325 rule: None,
326 })),
327 },
328 args[0].to_owned(),
329 head.to_owned(),
330 ]));
331 preprocess_expr(&code, scope_defs, file_ns, check_warnings, call_stack)
332 } else {
333 Err(CalcitErr::use_msg_stack(format!("{} expected single argument", head), call_stack))
334 }
335 }
336 (
337 _,
338 Some(Calcit::Macro {
339 name,
340 def_ns,
341 args: def_args,
342 body,
343 ..
344 }),
345 ) => {
346 let mut current_values = Box::new(args.to_owned());
347
348 let code = Calcit::List(xs.to_owned());
352 let next_stack = extend_call_stack(call_stack, def_ns.to_owned(), name.to_owned(), StackKind::Macro, code, &args);
353
354 loop {
355 let body_scope = runner::bind_args(def_args, ¤t_values, &rpds::HashTrieMap::new_sync(), &next_stack)?;
358 let code = runner::evaluate_lines(body, &body_scope, def_ns.to_owned(), &next_stack)?;
359 match code {
360 Calcit::Recur(ys) => {
361 current_values = Box::new(ys.to_owned());
362 }
363 _ => {
364 return preprocess_expr(&code, scope_defs, file_ns, check_warnings, &next_stack);
366 }
367 }
368 }
369 }
370 (Calcit::Syntax(name, name_ns), _) => match name {
371 CalcitSyntax::Quasiquote => Ok((
372 preprocess_quasiquote(name, name_ns.to_owned(), &args, scope_defs, file_ns, check_warnings, call_stack)?,
373 None,
374 )),
375 CalcitSyntax::Defn | CalcitSyntax::Defmacro => Ok((
376 preprocess_defn(name, name_ns.to_owned(), &args, scope_defs, file_ns, check_warnings, call_stack)?,
377 None,
378 )),
379 CalcitSyntax::CoreLet => Ok((
380 preprocess_call_let(name, name_ns.to_owned(), &args, scope_defs, file_ns, check_warnings, call_stack)?,
381 None,
382 )),
383 CalcitSyntax::If
384 | CalcitSyntax::Try
385 | CalcitSyntax::Macroexpand
386 | CalcitSyntax::MacroexpandAll
387 | CalcitSyntax::Macroexpand1
388 | CalcitSyntax::Reset => Ok((
389 preprocess_each_items(name, name_ns.to_owned(), &args, scope_defs, file_ns, check_warnings, call_stack)?,
390 None,
391 )),
392 CalcitSyntax::Quote | CalcitSyntax::Eval | CalcitSyntax::HintFn => {
393 Ok((preprocess_quote(name, name_ns.to_owned(), &args, scope_defs, file_ns)?, None))
394 }
395 CalcitSyntax::Defatom => Ok((
396 preprocess_defatom(name, name_ns.to_owned(), &args, scope_defs, file_ns, check_warnings, call_stack)?,
397 None,
398 )),
399 },
400 (Calcit::Thunk(..), _) => Err(CalcitErr::use_msg_stack(
401 format!("does not know how to preprocess a thunk: {}", head),
402 call_stack,
403 )),
404
405 (
406 _,
407 Some(Calcit::Fn {
408 name: f_name,
409 args: f_args,
410 ..
411 }),
412 ) => {
413 check_fn_args(f_args, &args, file_ns.to_owned(), f_name.to_owned(), def_name, check_warnings);
414 let mut ys = Vec::with_capacity(args.len() + 1);
415 ys.push(head_form);
416 for a in &args {
417 let (form, _v) = preprocess_expr(a, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?;
418 ys.push(form);
419 }
420 Ok((Calcit::List(TernaryTreeList::from(&ys)), None))
421 }
422 (_, _) => {
423 let mut ys = Vec::with_capacity(args.len() + 1);
424 ys.push(head_form);
425 for a in &args {
426 let (form, _v) = preprocess_expr(a, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?;
427 ys.push(form);
428 }
429 Ok((Calcit::List(TernaryTreeList::from(&ys)), None))
430 }
431 }
432}
433
434fn check_fn_args(
436 defined_args: &[Arc<str>],
437 params: &CalcitItems,
438 file_ns: Arc<str>,
439 f_name: Arc<str>,
440 def_name: Arc<str>,
441 check_warnings: &RefCell<Vec<String>>,
442) {
443 let mut i = 0;
444 let mut j = 0;
445 let mut optional = false;
446
447 loop {
448 let d = defined_args.get(i);
449 let r = params.get(j);
450
451 match (d, r) {
452 (None, None) => return,
453 (_, Some(Calcit::Symbol { sym, .. })) if &**sym == "&" => {
454 return;
456 }
457 (Some(sym), _) if &**sym == "&" => {
458 return;
460 }
461 (Some(sym), _) if &**sym == "?" => {
462 optional = true;
464 i += 1;
465 continue;
466 }
467 (Some(_), None) => {
468 if optional {
469 i += 1;
470 j += 1;
471 continue;
472 } else {
473 let mut warnings = check_warnings.borrow_mut();
474 warnings.push(format!(
475 "[Warn] lack of args in {} `{:?}` with `{}`, at {}/{}",
476 f_name,
477 defined_args,
478 primes::CrListWrap(params.to_owned()),
479 file_ns,
480 def_name
481 ));
482 return;
483 }
484 }
485 (None, Some(_)) => {
486 let mut warnings = check_warnings.borrow_mut();
487 warnings.push(format!(
488 "[Warn] too many args for {} `{:?}` with `{}`, at {}/{}",
489 f_name,
490 defined_args,
491 primes::CrListWrap(params.to_owned()),
492 file_ns,
493 def_name
494 ));
495 return;
496 }
497 (Some(_), Some(_)) => {
498 i += 1;
499 j += 1;
500 continue;
501 }
502 }
503 }
504}
505
506fn grab_def_name(x: &Calcit) -> Arc<str> {
508 match x {
509 Calcit::Symbol { at_def: def_name, .. } => def_name.to_owned(),
510 _ => String::from("??").into(),
511 }
512}
513
514pub fn preprocess_each_items(
516 head: &CalcitSyntax,
517 head_ns: Arc<str>,
518 args: &CalcitItems,
519 scope_defs: &HashSet<Arc<str>>,
520 file_ns: Arc<str>,
521 check_warnings: &RefCell<Vec<String>>,
522 call_stack: &CallStackList,
523) -> Result<Calcit, CalcitErr> {
524 let mut xs: CalcitItems = TernaryTreeList::from(&[Calcit::Syntax(head.to_owned(), head_ns)]);
525 for a in args {
526 let (form, _v) = preprocess_expr(a, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?;
527 xs = xs.push_right(form);
528 }
529 Ok(Calcit::List(xs))
530}
531
532pub fn preprocess_defn(
533 head: &CalcitSyntax,
534 head_ns: Arc<str>,
535 args: &CalcitItems,
536 scope_defs: &HashSet<Arc<str>>,
537 file_ns: Arc<str>,
538 check_warnings: &RefCell<Vec<String>>,
539 call_stack: &CallStackList,
540) -> Result<Calcit, CalcitErr> {
541 let mut xs: CalcitItems = TernaryTreeList::from(&[Calcit::Syntax(head.to_owned(), head_ns)]);
543 match (args.get(0), args.get(1)) {
544 (
545 Some(Calcit::Symbol {
546 sym: def_name,
547 ns: def_name_ns,
548 at_def,
549 ..
550 }),
551 Some(Calcit::List(ys)),
552 ) => {
553 let mut body_defs: HashSet<Arc<str>> = scope_defs.to_owned();
554
555 xs = xs.push_right(Calcit::Symbol {
556 sym: def_name.to_owned(),
557 ns: def_name_ns.to_owned(),
558 at_def: at_def.to_owned(),
559 resolved: Some(Arc::new(ResolvedRaw)),
560 });
561 let mut zs: CalcitItems = TernaryTreeList::Empty;
562 for y in ys {
563 match y {
564 Calcit::Symbol {
565 sym, ns: def_ns, at_def, ..
566 } => {
567 check_symbol(sym, args, check_warnings);
568 zs = zs.push_right(Calcit::Symbol {
569 sym: sym.to_owned(),
570 ns: def_ns.to_owned(),
571 at_def: at_def.to_owned(),
572 resolved: Some(Arc::new(ResolvedRaw)),
573 });
574 if &**sym != "&" && &**sym != "?" {
576 body_defs.insert(sym.to_owned());
577 }
578 }
579 _ => {
580 return Err(CalcitErr::use_msg_stack(
581 format!("expected defn args to be symbols, got: {}", y),
582 call_stack,
583 ))
584 }
585 }
586 }
587 xs = xs.push_right(Calcit::List(zs));
588
589 for (idx, a) in args.into_iter().enumerate() {
590 if idx >= 2 {
591 let (form, _v) = preprocess_expr(a, &body_defs, file_ns.to_owned(), check_warnings, call_stack)?;
592 xs = xs.push_right(form);
593 }
594 }
595 Ok(Calcit::List(xs))
596 }
597 (Some(a), Some(b)) => Err(CalcitErr::use_msg_stack(
598 format!("defn/defmacro expected name and args: {} {}", a, b),
599 call_stack,
600 )),
601 (a, b) => Err(CalcitErr::use_msg_stack(
602 format!("defn or defmacro expected name and args, got {:?} {:?}", a, b,),
603 call_stack,
604 )),
605 }
606}
607
608fn check_symbol(sym: &str, args: &CalcitItems, check_warnings: &RefCell<Vec<String>>) {
610 if is_proc_name(sym) || CalcitSyntax::is_core_syntax(sym) || program::has_def_code(primes::CORE_NS, sym) {
611 let mut warnings = check_warnings.borrow_mut();
612 warnings.push(format!(
613 "[Warn] local binding `{}` shadowed `calcit.core/{}`, with {}",
614 sym,
615 sym,
616 primes::CrListWrap(args.to_owned())
617 ));
618 }
619}
620
621pub fn preprocess_call_let(
622 head: &CalcitSyntax,
623 head_ns: Arc<str>,
624 args: &CalcitItems,
625 scope_defs: &HashSet<Arc<str>>,
626 file_ns: Arc<str>,
627 check_warnings: &RefCell<Vec<String>>,
628 call_stack: &CallStackList,
629) -> Result<Calcit, CalcitErr> {
630 let mut xs: CalcitItems = TernaryTreeList::from(&[Calcit::Syntax(head.to_owned(), head_ns)]);
631 let mut body_defs: HashSet<Arc<str>> = scope_defs.to_owned();
632 let binding = match args.get(0) {
633 Some(Calcit::Nil) => Calcit::Nil,
634 Some(Calcit::List(ys)) if ys.len() == 2 => match (&ys[0], &ys[1]) {
635 (Calcit::Symbol { sym, .. }, a) => {
636 check_symbol(sym, args, check_warnings);
637 body_defs.insert(sym.to_owned());
638 let (form, _v) = preprocess_expr(a, &body_defs, file_ns.to_owned(), check_warnings, call_stack)?;
639 Calcit::List(TernaryTreeList::from(&[ys[0].to_owned(), form]))
640 }
641 (a, b) => {
642 return Err(CalcitErr::use_msg_stack(
643 format!("invalid pair for &let binding: {} {}", a, b),
644 call_stack,
645 ))
646 }
647 },
648 Some(Calcit::List(ys)) => {
649 return Err(CalcitErr::use_msg_stack(
650 format!("expected binding of a pair, got {:?}", ys),
651 call_stack,
652 ))
653 }
654 Some(a) => {
655 return Err(CalcitErr::use_msg_stack(
656 format!("expected binding of a pair, got {}", a),
657 call_stack,
658 ))
659 }
660 None => {
661 return Err(CalcitErr::use_msg_stack(
662 "expected binding of a pair, got nothing".to_owned(),
663 call_stack,
664 ))
665 }
666 };
667 xs = xs.push_right(binding);
668 for (idx, a) in args.into_iter().enumerate() {
669 if idx > 0 {
670 let (form, _v) = preprocess_expr(a, &body_defs, file_ns.to_owned(), check_warnings, call_stack)?;
671 xs = xs.push_right(form);
672 }
673 }
674 Ok(Calcit::List(xs))
675}
676
677pub fn preprocess_quote(
678 head: &CalcitSyntax,
679 head_ns: Arc<str>,
680 args: &CalcitItems,
681 _scope_defs: &HashSet<Arc<str>>,
682 _file_ns: Arc<str>,
683) -> Result<Calcit, CalcitErr> {
684 let mut xs: CalcitItems = TernaryTreeList::from(&[Calcit::Syntax(head.to_owned(), head_ns)]);
685 for a in args {
686 xs = xs.push_right(a.to_owned());
687 }
688 Ok(Calcit::List(xs))
689}
690
691pub fn preprocess_defatom(
692 head: &CalcitSyntax,
693 head_ns: Arc<str>,
694 args: &CalcitItems,
695 scope_defs: &HashSet<Arc<str>>,
696 file_ns: Arc<str>,
697 check_warnings: &RefCell<Vec<String>>,
698 call_stack: &CallStackList,
699) -> Result<Calcit, CalcitErr> {
700 let mut xs: CalcitItems = TernaryTreeList::from(&[Calcit::Syntax(head.to_owned(), head_ns)]);
701 for a in args {
702 let (form, _v) = preprocess_expr(a, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?;
704 xs = xs.push_right(form.to_owned());
705 }
706 Ok(Calcit::List(xs))
707}
708
709pub fn preprocess_quasiquote(
711 head: &CalcitSyntax,
712 head_ns: Arc<str>,
713 args: &CalcitItems,
714 scope_defs: &HashSet<Arc<str>>,
715 file_ns: Arc<str>,
716 check_warnings: &RefCell<Vec<String>>,
717 call_stack: &CallStackList,
718) -> Result<Calcit, CalcitErr> {
719 let mut xs: CalcitItems = TernaryTreeList::from(&[Calcit::Syntax(head.to_owned(), head_ns)]);
720 for a in args {
721 xs = xs.push_right(preprocess_quasiquote_internal(
722 a,
723 scope_defs,
724 file_ns.to_owned(),
725 check_warnings,
726 call_stack,
727 )?);
728 }
729 Ok(Calcit::List(xs))
730}
731
732pub fn preprocess_quasiquote_internal(
733 x: &Calcit,
734 scope_defs: &HashSet<Arc<str>>,
735 file_ns: Arc<str>,
736 check_warnings: &RefCell<Vec<String>>,
737 call_stack: &CallStackList,
738) -> Result<Calcit, CalcitErr> {
739 match x {
740 Calcit::List(ys) if ys.is_empty() => Ok(x.to_owned()),
741 Calcit::List(ys) => match &ys[0] {
742 Calcit::Symbol { sym, .. } if &**sym == "~" || &**sym == "~@" => {
743 let mut xs: CalcitItems = TernaryTreeList::Empty;
744 for y in ys {
745 let (form, _) = preprocess_expr(y, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?;
746 xs = xs.push_right(form.to_owned());
747 }
748 Ok(Calcit::List(xs))
749 }
750 _ => {
751 let mut xs: CalcitItems = TernaryTreeList::Empty;
752 for y in ys {
753 xs = xs.push_right(preprocess_quasiquote_internal(y, scope_defs, file_ns.to_owned(), check_warnings, call_stack)?.to_owned());
754 }
755 Ok(Calcit::List(xs))
756 }
757 },
758 _ => Ok(x.to_owned()),
759 }
760}