1mod syntax_name;
2
3use core::cmp::Ord;
4use std::cmp::Eq;
5use std::cmp::Ordering;
6use std::cmp::Ordering::*;
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
10use std::sync::Arc;
11
12use cirru_edn::EdnKwd;
13use im_ternary_tree::TernaryTreeList;
14
15static ID_GEN: AtomicUsize = AtomicUsize::new(0);
16
17pub use syntax_name::CalcitSyntax;
18
19use crate::call_stack::CallStackList;
20
21#[derive(Debug, Clone, PartialEq)]
22pub enum SymbolResolved {
23 ResolvedLocal,
24 ResolvedRaw, ResolvedDef {
26 ns: Arc<str>,
27 def: Arc<str>,
28 rule: Option<Arc<ImportRule>>,
29 }, }
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34pub enum ImportRule {
35 NsAs(Arc<str>), NsReferDef(Arc<str>, Arc<str>), NsDefault(Arc<str>), }
39
40pub type CalcitScope = rpds::HashTrieMapSync<Arc<str>, Calcit>;
42pub type CalcitItems = TernaryTreeList<Calcit>;
43
44#[derive(Debug, Clone, PartialEq, PartialOrd)]
46pub struct CrListWrap(pub TernaryTreeList<Calcit>);
47
48#[derive(Debug, Clone)]
49pub enum Calcit {
50 Nil,
51 Bool(bool),
52 Number(f64),
53 Symbol {
54 sym: Arc<str>,
55 ns: Arc<str>,
56 at_def: Arc<str>,
57 resolved: Option<Arc<SymbolResolved>>,
58 }, Keyword(EdnKwd),
60 Str(Arc<str>),
61 Thunk(Arc<Calcit>, Option<Arc<Calcit>>),
62 Ref(Arc<str>),
64 Tuple(Arc<Calcit>, Arc<Calcit>),
66 Buffer(Vec<u8>),
68 Recur(CalcitItems),
70 List(CalcitItems),
71 Set(rpds::HashTrieSetSync<Calcit>),
72 Map(rpds::HashTrieMapSync<Calcit, Calcit>),
73 Record(EdnKwd, Arc<Vec<EdnKwd>>, Arc<Vec<Calcit>>), Proc(Arc<str>),
75 Macro {
76 name: Arc<str>, def_ns: Arc<str>, id: Arc<str>, args: Arc<Vec<Arc<str>>>, body: Arc<CalcitItems>, },
82 Fn {
83 name: Arc<str>, def_ns: Arc<str>, id: Arc<str>, scope: Arc<CalcitScope>,
87 args: Arc<Vec<Arc<str>>>, body: Arc<CalcitItems>, },
90 Syntax(CalcitSyntax, Arc<str>), }
92
93impl fmt::Display for Calcit {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 match self {
96 Calcit::Nil => f.write_str("nil"),
97 Calcit::Bool(v) => f.write_str(&format!("{}", v)),
98 Calcit::Number(n) => f.write_str(&format!("{}", n)),
99 Calcit::Symbol { sym, .. } => f.write_str(&format!("'{}", sym)),
100 Calcit::Keyword(s) => f.write_str(&format!(":{}", s)),
101 Calcit::Str(s) => {
102 if is_simple_str(s) {
103 write!(f, "|{}", s)
104 } else {
105 write!(f, "\"|{}\"", s.escape_default())
106 }
107 } Calcit::Thunk(code, v) => match v {
109 Some(data) => f.write_str(&format!("(&thunk {} {})", data, code)),
110 None => f.write_str(&format!("(&thunk _ {})", code)),
111 },
112 Calcit::Ref(name) => f.write_str(&format!("(&ref {})", name)),
113 Calcit::Tuple(a, b) => f.write_str(&format!("(:: {} {})", a, b)),
114 Calcit::Buffer(buf) => {
115 f.write_str("(&buffer")?;
116 if buf.len() > 8 {
117 f.write_str(&format!(
118 " {} {} {} {} {} {} {} {} ..+{}",
119 buffer_bit_hex(buf[0]),
120 buffer_bit_hex(buf[1]),
121 buffer_bit_hex(buf[2]),
122 buffer_bit_hex(buf[3]),
123 buffer_bit_hex(buf[4]),
124 buffer_bit_hex(buf[5]),
125 buffer_bit_hex(buf[6]),
126 buffer_bit_hex(buf[7]),
127 buf.len() - 8
128 ))?;
129 } else {
130 for b in buf {
131 f.write_str(" ")?;
132 f.write_str(&buffer_bit_hex(b.to_owned()))?;
133 }
134 }
135 f.write_str(")")
136 }
137 Calcit::Recur(xs) => {
138 f.write_str("(&recur")?;
139 for x in xs {
140 f.write_str(&format!(" {}", x))?;
141 }
142 f.write_str(")")
143 }
144 Calcit::List(xs) => {
145 f.write_str("([]")?;
146 for x in xs {
147 f.write_str(&format!(" {}", x))?;
148 }
149 f.write_str(")")
150 }
151 Calcit::Set(xs) => {
152 f.write_str("(#{}")?;
153 for x in xs {
154 f.write_str(&format!(" {}", x))?;
155 }
156 f.write_str(")")
157 }
158 Calcit::Map(xs) => {
159 f.write_str("({}")?;
160 for (k, v) in xs {
161 f.write_str(&format!(" ({} {})", k, v))?;
162 }
163 f.write_str(")")?;
164 Ok(())
165 }
166 Calcit::Record(name, fields, values) => {
167 f.write_str(&format!("(%{{}} {}", Calcit::Keyword(name.to_owned())))?;
168 for idx in 0..fields.len() {
169 f.write_str(&format!(" ({} {})", Calcit::Keyword(fields[idx].to_owned()), values[idx]))?;
170 }
171 f.write_str(")")
172 }
173 Calcit::Proc(name) => f.write_str(&format!("(&proc {})", name)),
174 Calcit::Macro { name, args, body, .. } => {
175 f.write_str(&format!("(¯o {} (", name))?;
176 let mut need_space = false;
177 for a in &**args {
178 if need_space {
179 f.write_str(" ")?;
180 }
181 f.write_str(&**a)?;
182 need_space = true;
183 }
184 f.write_str(") (")?;
185 need_space = false;
186 for b in &**body {
187 if need_space {
188 f.write_str(" ")?;
189 }
190 f.write_str(&format_to_lisp(b))?;
191 need_space = true;
192 }
193 f.write_str("))")
194 }
195 Calcit::Fn { name, args, body, .. } => {
196 f.write_str(&format!("(&fn {} (", name))?;
197 let mut need_space = false;
198 for a in &**args {
199 if need_space {
200 f.write_str(" ")?;
201 }
202 f.write_str(&**a)?;
203 need_space = true;
204 }
205 f.write_str(") ")?;
206 need_space = false;
207 for b in &**body {
208 if need_space {
209 f.write_str(" ")?;
210 }
211 f.write_str(&format_to_lisp(b))?;
212 need_space = true;
213 }
214 f.write_str(")")
215 }
216 Calcit::Syntax(name, _ns) => f.write_str(&format!("(&syntax {})", name)),
217 }
218 }
219}
220
221fn is_simple_str(tok: &str) -> bool {
222 for c in tok.chars() {
223 if !matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '?' | '!' | '|') {
224 return false;
225 }
226 }
227 true
228}
229
230fn buffer_bit_hex(n: u8) -> String {
231 hex::encode(vec![n])
232}
233
234impl fmt::Display for CrListWrap {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 f.write_str(&format_to_lisp(&Calcit::List(self.0.to_owned()))) }
239}
240
241pub fn format_to_lisp(x: &Calcit) -> String {
243 match x {
244 Calcit::List(ys) => {
245 let mut s = String::from("(");
246 for (idx, y) in ys.into_iter().enumerate() {
247 if idx > 0 {
248 s.push(' ');
249 }
250 s.push_str(&format_to_lisp(y));
251 }
252 s.push(')');
253 s
254 }
255 Calcit::Symbol { sym, .. } => sym.to_string(),
256 Calcit::Syntax(s, _ns) => s.to_string(),
257 Calcit::Proc(s) => s.to_string(),
258 a => format!("{}", a),
259 }
260}
261
262impl Hash for Calcit {
263 fn hash<H>(&self, _state: &mut H)
264 where
265 H: Hasher,
266 {
267 match self {
268 Calcit::Nil => "nil:".hash(_state),
269 Calcit::Bool(v) => {
270 "bool:".hash(_state);
271 v.hash(_state);
272 }
273 Calcit::Number(n) => {
274 "number:".hash(_state);
275 (*n as usize).hash(_state)
277 }
278 Calcit::Symbol { sym, .. } => {
279 "symbol:".hash(_state);
280 sym.hash(_state);
281 }
284 Calcit::Keyword(s) => {
285 "keyword:".hash(_state);
286 s.hash(_state);
287 }
288 Calcit::Str(s) => {
289 "string:".hash(_state);
290 s.hash(_state);
291 }
292 Calcit::Thunk(v, _) => {
293 "quote:".hash(_state);
294 v.hash(_state);
295 }
296 Calcit::Ref(name) => {
297 "ref:".hash(_state);
298 name.hash(_state);
299 }
300 Calcit::Tuple(a, b) => {
301 "tuple:".hash(_state);
302 a.hash(_state);
303 b.hash(_state);
304 }
305 Calcit::Buffer(buf) => {
306 "buffer:".hash(_state);
307 buf.hash(_state);
308 }
309 Calcit::Recur(v) => {
310 "list:".hash(_state);
311 v.hash(_state);
312 }
313 Calcit::List(v) => {
314 "list:".hash(_state);
315 v.hash(_state);
316 }
317 Calcit::Set(v) => {
318 "set:".hash(_state);
319 for x in v {
321 x.hash(_state)
322 }
323 }
324 Calcit::Map(v) => {
325 "map:".hash(_state);
326 for x in v {
328 x.hash(_state)
329 }
330 }
331 Calcit::Record(name, fields, values) => {
332 "record:".hash(_state);
333 name.hash(_state);
334 fields.hash(_state);
335 values.hash(_state);
336 }
337 Calcit::Proc(name) => {
338 "proc:".hash(_state);
339 name.hash(_state);
340 }
341 Calcit::Macro { id: gen_id, .. } => {
342 "macro:".hash(_state);
343 gen_id.hash(_state);
345 }
346 Calcit::Fn { id: gen_id, .. } => {
347 "fn:".hash(_state);
348 gen_id.hash(_state);
350 }
351 Calcit::Syntax(name, _ns) => {
352 "syntax:".hash(_state);
353 name.to_string().hash(_state); }
356 }
357 }
358}
359
360impl Ord for Calcit {
361 fn cmp(&self, other: &Self) -> Ordering {
362 match (self, other) {
363 (Calcit::Nil, Calcit::Nil) => Equal,
364 (Calcit::Nil, _) => Less,
365 (_, Calcit::Nil) => Greater,
366
367 (Calcit::Bool(a), Calcit::Bool(b)) => a.cmp(b),
368 (Calcit::Bool(_), _) => Less,
369 (_, Calcit::Bool(_)) => Greater,
370
371 (Calcit::Number(a), Calcit::Number(b)) => {
372 if a < b {
373 Less
374 } else if a > b {
375 Greater
376 } else {
377 Equal
378 }
379 }
380 (Calcit::Number(_), _) => Less,
381 (_, Calcit::Number(_)) => Greater,
382
383 (Calcit::Symbol { sym: a, .. }, Calcit::Symbol { sym: b, .. }) => a.cmp(b),
384 (Calcit::Symbol { .. }, _) => Less,
385 (_, Calcit::Symbol { .. }) => Greater,
386
387 (Calcit::Keyword(a), Calcit::Keyword(b)) => a.cmp(b),
388 (Calcit::Keyword(_), _) => Less,
389 (_, Calcit::Keyword(_)) => Greater,
390
391 (Calcit::Str(a), Calcit::Str(b)) => a.cmp(b),
392 (Calcit::Str(_), _) => Less,
393 (_, Calcit::Str(_)) => Greater,
394
395 (Calcit::Thunk(a, _), Calcit::Thunk(b, _)) => a.cmp(b),
396 (Calcit::Thunk(_, _), _) => Less,
397 (_, Calcit::Thunk(_, _)) => Greater,
398
399 (Calcit::Ref(a), Calcit::Ref(b)) => a.cmp(b),
400 (Calcit::Ref(_), _) => Less,
401 (_, Calcit::Ref(_)) => Greater,
402
403 (Calcit::Tuple(a0, b0), Calcit::Tuple(a1, b1)) => match a0.cmp(a1) {
404 Equal => b0.cmp(b1),
405 v => v,
406 },
407 (Calcit::Tuple(_, _), _) => Less,
408 (_, Calcit::Tuple(_, _)) => Greater,
409
410 (Calcit::Buffer(buf1), Calcit::Buffer(buf2)) => buf1.cmp(buf2),
411 (Calcit::Buffer(..), _) => Less,
412 (_, Calcit::Buffer(..)) => Greater,
413
414 (Calcit::Recur(a), Calcit::Recur(b)) => a.cmp(b),
415 (Calcit::Recur(_), _) => Less,
416 (_, Calcit::Recur(_)) => Greater,
417
418 (Calcit::List(a), Calcit::List(b)) => a.cmp(b),
419 (Calcit::List(_), _) => Less,
420 (_, Calcit::List(_)) => Greater,
421
422 (Calcit::Set(a), Calcit::Set(b)) => match a.size().cmp(&b.size()) {
423 Equal => {
424 if a == b {
425 Equal
426 } else {
427 unreachable!("TODO sets are not cmp ed") }
429 }
430 a => a,
431 },
432 (Calcit::Set(_), _) => Less,
433 (_, Calcit::Set(_)) => Greater,
434
435 (Calcit::Map(a), Calcit::Map(b)) => {
436 unreachable!("TODO maps are not cmp ed {:?} {:?}", a, b)
437 }
439 (Calcit::Map(_), _) => Less,
440 (_, Calcit::Map(_)) => Greater,
441
442 (Calcit::Record(_name1, _fields1, _values1), Calcit::Record(_name2, _fields2, _values2)) => {
443 unreachable!("TODO records are not cmp ed") }
445 (Calcit::Record(..), _) => Less,
446 (_, Calcit::Record(..)) => Greater,
447
448 (Calcit::Proc(a), Calcit::Proc(b)) => a.cmp(b),
449 (Calcit::Proc(_), _) => Less,
450 (_, Calcit::Proc(_)) => Greater,
451
452 (Calcit::Macro { id: a, .. }, Calcit::Macro { id: b, .. }) => a.cmp(b),
453 (Calcit::Macro { .. }, _) => Less,
454 (_, Calcit::Macro { .. }) => Greater,
455
456 (Calcit::Fn { id: a, .. }, Calcit::Fn { id: b, .. }) => a.cmp(b), (Calcit::Fn { .. }, _) => Less,
458 (_, Calcit::Fn { .. }) => Greater,
459
460 (Calcit::Syntax(a, _), Calcit::Syntax(b, _)) => a.cmp(b),
461 }
462 }
463}
464
465impl PartialOrd for Calcit {
466 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
467 Some(self.cmp(other))
468 }
469}
470
471impl Eq for Calcit {}
472
473impl PartialEq for Calcit {
474 fn eq(&self, other: &Self) -> bool {
475 match (self, other) {
476 (Calcit::Nil, Calcit::Nil) => true,
477 (Calcit::Bool(a), Calcit::Bool(b)) => a == b,
478 (Calcit::Number(a), Calcit::Number(b)) => a == b,
479 (Calcit::Symbol { sym: a, .. }, Calcit::Symbol { sym: b, .. }) => a == b,
480 (Calcit::Keyword(a), Calcit::Keyword(b)) => a == b,
481 (Calcit::Str(a), Calcit::Str(b)) => a == b,
482 (Calcit::Thunk(a, _), Calcit::Thunk(b, _)) => a == b,
483 (Calcit::Ref(a), Calcit::Ref(b)) => a == b,
484 (Calcit::Tuple(a, b), Calcit::Tuple(c, d)) => a == c && b == d,
485 (Calcit::Buffer(b), Calcit::Buffer(d)) => b == d,
486 (Calcit::List(a), Calcit::List(b)) => a == b,
487 (Calcit::Set(a), Calcit::Set(b)) => a == b,
488 (Calcit::Map(a), Calcit::Map(b)) => a == b,
489 (Calcit::Record(name1, fields1, values1), Calcit::Record(name2, fields2, values2)) => {
490 name1 == name2 && fields1 == fields2 && values1 == values2
491 }
492
493 (Calcit::Proc(a), Calcit::Proc(b)) => a == b,
495 (Calcit::Macro { id: a, .. }, Calcit::Macro { id: b, .. }) => a == b,
496 (Calcit::Fn { id: a, .. }, Calcit::Fn { id: b, .. }) => a == b,
497 (Calcit::Syntax(a, _), Calcit::Syntax(b, _)) => a == b,
498 (_, _) => false,
499 }
500 }
501}
502
503pub const CORE_NS: &str = "calcit.core";
504pub const BUILTIN_CLASSES_ENTRY: &str = "&init-builtin-classes!";
505pub const GENERATED_NS: &str = "calcit.gen";
506pub const GENERATED_DEF: &str = "gen%";
507
508lazy_static! {
509 pub static ref GEN_NS: Arc<str> = GENERATED_NS.to_string().into();
510 pub static ref GEN_DEF: Arc<str> = GENERATED_DEF.to_string().into();
511 pub static ref GEN_CORE_NS: Arc<str> = CORE_NS.to_string().into();
512 pub static ref GEN_CLASS_ENTRY: Arc<str> = BUILTIN_CLASSES_ENTRY.to_string().into();
513}
514
515impl Calcit {
516 pub fn turn_string(&self) -> String {
517 match self {
518 Calcit::Nil => String::from(""),
519 Calcit::Str(s) => (**s).to_owned(),
520 _ => format!("{}", self),
521 }
522 }
523
524 pub fn lisp_str(&self) -> String {
525 format_to_lisp(self)
526 }
527
528 pub fn new_str<T: Into<String>>(s: T) -> Calcit {
529 Calcit::Str(s.into().into())
530 }
531
532 pub fn kwd(s: &str) -> Self {
534 Calcit::Keyword(EdnKwd::from(s))
535 }
536}
537
538pub fn gen_core_id() -> Arc<str> {
540 let c = ID_GEN.fetch_add(1, SeqCst);
541 format!("gen_id_{}", c).into()
542}
543
544#[derive(Debug, Clone, PartialEq)]
545pub struct CalcitErr {
546 pub msg: String,
547 pub warnings: Vec<String>,
548 pub stack: rpds::ListSync<crate::call_stack::CalcitStack>,
549}
550
551impl fmt::Display for CalcitErr {
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 f.write_str(&self.msg)?;
554 if !self.warnings.is_empty() {
555 f.write_str("\n")?;
556 for w in &self.warnings {
557 writeln!(f, "{}", w)?;
558 }
559 }
560 Ok(())
561 }
562}
563
564impl From<String> for CalcitErr {
565 fn from(msg: String) -> Self {
567 CalcitErr {
568 msg,
569 warnings: vec![],
570 stack: rpds::List::new_sync(),
571 }
572 }
573}
574
575impl CalcitErr {
576 pub fn use_str<T: Into<String>>(msg: T) -> Self {
577 CalcitErr {
578 msg: msg.into(),
579 warnings: vec![],
580 stack: rpds::List::new_sync(),
581 }
582 }
583 pub fn err_str<T: Into<String>>(msg: T) -> Result<Calcit, Self> {
584 Err(CalcitErr {
585 msg: msg.into(),
586 warnings: vec![],
587 stack: rpds::List::new_sync(),
588 })
589 }
590 pub fn use_msg_stack<T: Into<String>>(msg: T, stack: &CallStackList) -> Self {
591 CalcitErr {
592 msg: msg.into(),
593 warnings: vec![],
594 stack: stack.to_owned(),
595 }
596 }
597}