1pub mod structs;
4use structs::*;
5
6pub(crate) mod fns;
7
8pub(crate) mod cmds;
9
10pub(crate) mod errors;
11
12pub(crate) mod conv;
13
14pub(crate) mod num;
15
16#[cfg(not(feature = "no_os"))]
17mod os;
18
19use std::cell::LazyCell;
20use std::io::{Write, BufRead, ErrorKind};
21use std::ptr::NonNull;
22use std::str::FromStr;
23use std::sync::{Arc, Mutex, mpsc::{Receiver, TryRecvError, RecvTimeoutError}};
24use linefeed::{DefaultTerminal, Interface};
25use bitvec::prelude::*;
26use malachite::{Natural, Integer, Rational};
27use malachite::base::num::arithmetic::traits::{DivRem, NegAssign, Pow};
28use malachite::base::num::basic::traits::{NegativeOne, Zero, One};
29use malachite::base::num::conversion::traits::{ConvertibleFrom, PowerOf2DigitIterable, PowerOf2Digits, RoundingFrom, WrappingFrom};
30use malachite::base::num::random::RandomPrimitiveInts;
31use malachite::base::rational_sequences::RationalSequence;
32use malachite::base::rounding_modes::RoundingMode;
33
34pub const STATE_FILE_HEADER: [u8;20] = *b"# ADC state file v1\n";
36
37struct LineEditor(Interface<DefaultTerminal>);
38impl Default for LineEditor {
39 fn default() -> Self {
40 use linefeed::Signal::*;
41 let iface = Interface::new("").unwrap();
42 iface.set_report_signal(Break, true);
44 iface.set_report_signal(Interrupt, true);
45 iface.set_report_signal(Quit, true);
46 Self(iface)
47 }
48}
49
50pub trait ReadLine {
54 fn read_line(&mut self) -> std::io::Result<String>;
58
59 fn clear_history(&mut self);
61}
62impl<T: BufRead> ReadLine for T {
63 fn read_line(&mut self) -> std::io::Result<String> {
64 let mut buf = String::new();
65 self.read_line(&mut buf)?;
66 Ok(buf)
67 }
68
69 fn clear_history(&mut self) {
70 }
72}
73impl ReadLine for LineEditor {
74 fn read_line(&mut self) -> std::io::Result<String> {
75 use linefeed::{ReadResult, Signal};
76 match self.0.read_line() {
77 Ok(ReadResult::Input(s)) => {
78 self.0.add_history_unique(s.clone());
79 Ok(s)
80 },
81 Ok(ReadResult::Eof) => {Err(ErrorKind::UnexpectedEof.into())},
82 Ok(ReadResult::Signal(sig)) => {
83 self.0.cancel_read_line()?;
84 match sig {
85 Signal::Break | Signal::Interrupt | Signal::Quit => {Err(ErrorKind::Interrupted.into())},
86 Signal::Continue => {Err(std::io::Error::other("Unhandled SIGCONT"))},
87 Signal::Suspend => {Err(std::io::Error::other("Unhandled SIGTSTP"))},
88 Signal::Resize => {Err(std::io::Error::other("Unhandled window resize"))},
89 }
90 },
91 Err(e) => {Err(e)}
92 }
93 }
94
95 fn clear_history(&mut self) {
96 self.0.clear_history();
97 }
98}
99
100pub struct IOStreams (
102 pub Box<dyn ReadLine + Send>,
104 pub Box<dyn Write + Send>,
106 pub Box<dyn Write + Send>
108);
109impl IOStreams {
110 pub fn empty() -> Self {
112 Self (
113 Box::new(std::io::empty()),
114 Box::new(std::io::empty()),
115 Box::new(std::io::empty())
116 )
117 }
118
119 pub fn process() -> Self {
121 Self (
122 Box::new(LineEditor::default()),
123 Box::new(std::io::stdout()),
124 Box::new(std::io::stderr())
125 )
126 }
127}
128
129#[derive(Debug, PartialEq, Eq, Clone, Copy)]
131pub enum LogLevel {
132 Normal,
134 Debug,
136 Quiet
138}
139
140lazy_static::lazy_static! {
141 pub(crate) static ref RE_CACHE: RegexCache = RegexCache::default();
142}
143
144fn rng_preset(bytes: [u8; 32]) -> RandomPrimitiveInts<u64> {
145 malachite::base::num::random::random_primitive_ints(malachite::base::random::Seed::from_bytes(bytes))
146}
147
148fn rng_os() -> RandomPrimitiveInts<u64> {
149 let mut bytes = [0u8; 32];
150 getrandom::fill(&mut bytes).unwrap();
151 rng_preset(bytes)
152}
153
154#[derive(Default, Clone, Copy)]
155enum Command {
156 Fn1(fns::Mon),
158
159 Fn2(fns::Dya),
161
162 Fn3(fns::Tri),
164
165 Cmd(cmds::Cmd),
167
168 Exec,
170
171 ExecR,
173
174 Lit,
176
177 Space,
179
180 #[default] Wrong,
182}
183
184const CMDS: [Command; 256] = {
186 use Command::*;
187 use fns::*;
188 use cmds::*;
189 [
190 Space, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Space, Space, Space, Space, Space, Wrong, Wrong,
192
193 Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong,
195
196 Space, Fn1(neg), Exec, Space, Wrong, Fn2(r#mod), Wrong, Lit, Exec, Exec, Fn2(mul), Fn2(add), Wrong, Fn2(sub), Lit, Fn2(div),
198
199 Lit, Lit, Lit, Lit, Lit, Lit, Lit, Lit, Lit, Lit, Exec, Wrong, Fn2(lt), Fn2(eq), Fn2(gt), Exec,
201
202 Lit, Wrong, Wrong, Cmd(cln), Exec, Wrong, Lit, Fn2(logb), Wrong, Cmd(gi), ExecR, Cmd(gk), ExecR, Cmd(gm), Wrong, Cmd(go),
204
205 Exec, Exec, Exec, ExecR, Lit, Wrong, Wrong, Wrong, ExecR, Wrong, ExecR, Lit, Wrong, Wrong, Fn2(pow), Exec,
207
208 Exec, Exec, Wrong, Cmd(cls), Exec, Wrong, Exec, Fn1(log), Wrong, Cmd(si), ExecR, Cmd(sk), ExecR, Cmd(sm), Wrong, Cmd(so),
210
211 Exec, Exec, Cmd(rev), ExecR, Wrong, Wrong, Wrong, Exec, Exec, Wrong, Fn1(disc), Cmd(cbo), Fn3(bar), Cmd(cbc), Fn2(euc), Wrong,
213
214 Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,
216 Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,
217 Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,
218 Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong,Wrong
219 ]
220};
221
222fn byte_cmd(b: u8) -> Command {
223 unsafe { *CMDS.get_unchecked(b as usize)
225 }
226}
227
228fn string_or_bytes(v: &[u8]) -> String {
229 str::from_utf8(v).map(|s| s.to_owned()).unwrap_or_else(|_| {
230 let mut res = String::from("(not UTF-8: [");
231 for b in v {
232 res += &format!("\\{b:02X}");
233 }
234 res += "])";
235 res
236 })
237}
238
239fn upper_hex_to_nibble(b: u8) -> Option<u8> {
240 match b {
241 b'0'..=b'9' => Some(unsafe{b.unchecked_sub(0x30)}), b'A'..=b'F' => Some(unsafe{b.unchecked_sub(0x37)}),
243 _ => None
244 }
245}
246
247fn mixed_ascii_to_digit(b: u8) -> Option<u8> {
248 match b {
249 b'0'..=b'9' => Some(unsafe{b.unchecked_sub(0x30)}), b'A'..=b'Z' => Some(unsafe{b.unchecked_sub(0x37)}),
251 b'a'..=b'z' => Some(unsafe{b.unchecked_sub(0x57)}),
252 _ => None
253 }
254}
255
256fn reg_index_nice(ri: &Rational) -> String {
257 Natural::try_from(ri).ok().and_then(|n| { let bytes: Vec<u8> = n.to_power_of_2_digits_desc(8); str::from_utf8(&bytes).ok().map(|s| String::from("[") + s + "]") })
261 .unwrap_or_else(|| {
262 num::nauto(ri, DEFAULT_PARAMS.0, &DEFAULT_PARAMS.2) })
264}
265
266#[derive(Clone, Copy, Debug, PartialEq)]
268#[must_use] pub enum ExecResult {
269 Finished,
271
272 SoftQuit(u8),
274
275 HardQuit(u8)
277}
278
279#[cold] #[inline(never)] pub fn interpreter(
298 st: &mut State,
299 start: Utf8Iter,
300 io: Arc<Mutex<IOStreams>>,
301 mut ll: LogLevel,
302 kill: Option<&Receiver<()>>,
303 mut restrict: bool
304 ) -> std::io::Result<ExecResult>
305{
306 use ExecResult::*;
307
308 let th_name = if kill.is_some() {
309 std::thread::current().name().unwrap().to_owned()
310 }
311 else {
312 String::new()
313 };
314
315 let mut pbuf: Option<String> = None; let mut elatch: Option<(Natural, char, String)> = None;
318
319 macro_rules! synerr {
320 ($c:expr, $s:expr) => {
321 if ll != LogLevel::Quiet {
322 let err = &mut io.lock().unwrap().2;
323 writeln!(err, "! {th_name}{}: {}", $c, $s)?;
324 err.flush()?;
325 }
326 elatch = Some((Natural::ZERO, $c, $s.into()));
327 };
328 ($c:expr, $f:literal, $($s:expr),*) => {
329 let s = format!($f, $($s),*);
330 if ll != LogLevel::Quiet {
331 let err = &mut io.lock().unwrap().2;
332 writeln!(err, "! {th_name}{}: {}", $c, s)?;
333 err.flush()?;
334 }
335 elatch = Some((Natural::ZERO, $c, s));
336 };
337 }
338
339 macro_rules! valerr {
340 ($c:expr, $s:expr) => {
341 if ll != LogLevel::Quiet {
342 let err = &mut io.lock().unwrap().2;
343 writeln!(err, "? {th_name}{}: {}", $c, $s)?;
344 err.flush()?;
345 }
346 elatch = Some((Natural::ZERO, $c, $s.into()));
347 };
348 ($c:expr, $f:literal, $($s:expr),*) => {
349 let s = format!($f, $($s),*);
350 if ll != LogLevel::Quiet {
351 let err = &mut io.lock().unwrap().2;
352 writeln!(err, "? {th_name}{}: {}", $c, s)?;
353 err.flush()?;
354 }
355 elatch = Some((Natural::ZERO, $c, s));
356 };
357 }
358
359 let mut rptr: Option<Rational> = None; let mut rng = LazyCell::new(rng_os);
379
380 let mut call: Vec<(Utf8Iter, Natural)> = vec![(start, Natural::const_from(1))];
381
382 'mac: while let Some((mac, count)) = call.last_mut() { *count -= Natural::ONE;
384 let mut alt = false;
385
386 let mut abuf: Vec<Value> = Vec::new(); let mut dest: Vec<NonNull<Vec<Value>>> = Vec::new(); macro_rules! push {
390 ($v:expr) => {
391 if let Some(p) = dest.last_mut() {
392 unsafe {
393 p.as_mut().push($v); }
395 }
396 else {
397 st.mstk.push(Arc::new($v));
398 }
399 };
400 }
401 macro_rules! append {
403 ($v:expr) => {
404 if let Some(p) = dest.last_mut() {
405 unsafe {
406 p.as_mut().append(&mut $v); }
408 }
409 else {
410 for val in $v {
411 st.mstk.push(Arc::new(val));
412 }
413 }
414 };
415 }
416
417 'cmd: while let Some(b) = mac.next() { if let Some(rx) = kill { match rx.try_recv() {
420 Ok(()) => { return Ok(Finished);
422 },
423 Err(TryRecvError::Empty) => { },
426 Err(TryRecvError::Disconnected) => { unreachable!()
428 }
429 }
430 }
431
432 if let Some(e) = &mut elatch { e.0 += Natural::ONE;
434 }
435
436 use Command::*;
437 match byte_cmd(b) {
438 Fn1(mon) => {
439 if let Some(va) = st.mstk.pop() {
440 match fns::exec1(mon, &va, alt) {
441 Ok(vz) => {
442 push!(vz);
443 }
444 Err(e) => {
445 st.mstk.push(va);
446 valerr!(b as char, e.to_string());
447 }
448 }
449 }
450 else {
451 synerr!(b as char, "Expected 1 argument, 0 given");
452 }
453 },
454 Fn2(dya) => {
455 if let Some(vb) = st.mstk.pop() {
456 if let Some(va) = st.mstk.pop() {
457 match fns::exec2(dya, &va, &vb, alt) {
458 Ok(vz) => {
459 push!(vz);
460 }
461 Err(e) => {
462 st.mstk.push(va);
463 st.mstk.push(vb);
464 valerr!(b as char, e.to_string());
465 }
466 }
467 }
468 else {
469 st.mstk.push(vb);
470 synerr!(b as char, "Expected 2 arguments, 1 given");
471 }
472 }
473 else {
474 synerr!(b as char, "Expected 2 arguments, 0 given");
475 }
476 },
477 Fn3(tri) => {
478 if let Some(vc) = st.mstk.pop() {
479 if let Some(vb) = st.mstk.pop() {
480 if let Some(va) = st.mstk.pop() {
481 match fns::exec3(tri, &va, &vb, &vc, alt) {
482 Ok(vz) => {
483 push!(vz);
484 }
485 Err(e) => {
486 st.mstk.push(va);
487 st.mstk.push(vb);
488 st.mstk.push(vc);
489 valerr!(b as char, e.to_string());
490 }
491 }
492 }
493 else {
494 st.mstk.push(vb);
495 st.mstk.push(vc);
496 synerr!(b as char, "Expected 3 arguments, 2 given");
497 }
498 }
499 else {
500 st.mstk.push(vc);
501 synerr!(b as char, "Expected 3 arguments, 1 given");
502 }
503 }
504 else {
505 synerr!(b as char, "Expected 3 arguments, 0 given");
506 }
507 },
508 Cmd(cmd) => {
509 match cmd(st) {
510 Ok(mut v) => {
511 append!(v);
512 }
513 Err(e) => {
514 if let Some(se) = e.strip_suffix('!') {
515 synerr!(b as char, se);
516 }
517 else {
518 valerr!(b as char, e);
519 }
520 }
521 }
522 },
523 Exec => {
524 match b {
525 b'`' => { alt = true;
527 continue 'cmd; },
529 b':' => { if let Some(va) = st.mstk.pop() {
531 if let Value::N(r) = &*va {
532 rptr = Some(r.clone());
533 }
534 else {
535 let ta = errors::TypeLabel::from(&*va);
536 st.mstk.push(va);
537 synerr!(':', "Expected a number, {} given", ta);
538 }
539 }
540 else {
541 synerr!(':', "Expected 1 argument, 0 given");
542 }
543 },
544 b'd' => {
545 if let Some(v) = st.mstk.last() {
546 if let Some(p) = dest.last_mut() { unsafe {
548 p.as_mut().push((**v).clone()); }
550 }
551 else {
552 st.mstk.push(Arc::clone(v));
553 }
554 }
555 else {
556 synerr!('d', "Stack is empty");
557 }
558 },
559 b'D' => {
560 if let Some(va) = st.mstk.pop() {
561 if let Value::N(r) = &*va {
562 match usize::try_from(r) {
563 Ok(0) => {}, Ok(u) => {
565 if let Some(from) = st.mstk.len().checked_sub(u) {
566 if let Some(p) = dest.last_mut() { for v in &st.mstk[from..] {
568 unsafe {
569 p.as_mut().push((**v).clone()); }
571 }
572 }
573 else {
574 st.mstk.extend_from_within(from..);
575 }
576 }
577 else {
578 st.mstk.push(va);
579 valerr!('D', "Can't duplicate {} values, stack depth is {}", u, st.mstk.len() - 1);
580 }
581 }
582 Err(_) => {
583 let vs = va.to_string();
584 st.mstk.push(va);
585 valerr!('D', "Can't possibly duplicate {} values", vs);
586 }
587 }
588 }
589 else {
590 let ta = errors::TypeLabel::from(&*va);
591 st.mstk.push(va);
592 synerr!('D', "Expected a number, {} given", ta);
593 }
594 }
595 else {
596 synerr!('D', "Expected 1 argument, 0 given");
597 }
598 },
599 b'R' => { if let Some(va) = st.mstk.pop() {
601 if let Value::N(r) = &*va {
602 match usize::try_from(r) {
603 Ok(0) => {}, Ok(u) => {
605 if let Some(from) = st.mstk.len().checked_sub(u) {
606 if alt {st.mstk[from..].rotate_left(1);}
607 else {st.mstk[from..].rotate_right(1);}
608 }
609 else {
610 st.mstk.push(va);
611 valerr!('R', "Can't rotate {} values, stack depth is {}", u, st.mstk.len() - 1);
612 }
613 }
614 Err(_) => {
615 let vs = va.to_string();
616 st.mstk.push(va);
617 valerr!('R', "Can't possibly rotate {} values", vs);
618 }
619 }
620 }
621 else {
622 let ta = errors::TypeLabel::from(&*va);
623 st.mstk.push(va);
624 synerr!('R', "Expected a number, {} given", ta);
625 }
626 }
627 else {
628 synerr!('R', "Expected 1 argument, 0 given");
629 }
630 },
631 b'?' => { let res = {io.lock().unwrap().0.read_line()}; match res {
634 Ok(s) => {
635 push!(Value::S(s));
636 },
637 Err(e) => {
638 match e.kind() {
639 ErrorKind::Interrupted => {
640 valerr!('?', "Interrupted");
641 },
642 ErrorKind::UnexpectedEof => {
643 push!(Value::S(String::new()));
644 },
645 _ => {
646 return Err(e);
647 }
648 }
649 }
650 }
651 },
652 b'p' => { if let Some(va) = st.mstk.pop() {
654 let vs = va.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
655 if let Some(s) = &mut pbuf {
656 s.push_str(&vs);
657 s.push('\n');
658 }
659 else {
660 let out = &mut io.lock().unwrap().1;
661 writeln!(out, "{}", vs)?;
662 out.flush()?;
663 }
664 }
665 else {
666 synerr!('p', "Expected 1 argument, 0 given");
667 }
668 },
669 b'P' => { if let Some(va) = st.mstk.pop() {
671 let vs = va.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
672 if let Some(s) = &mut pbuf {
673 s.push_str(&vs);
674 }
675 else {
676 let out = &mut io.lock().unwrap().1;
677 write!(out, "{}", vs)?;
678 out.flush()?;
679 }
680 }
681 else {
682 synerr!('P', "Expected 1 argument, 0 given");
683 }
684 },
685 b'"' => { if let Some(s) = pbuf.take() { push!(Value::S(s));
688 }
689 else { pbuf = Some(String::new());
691 }
692 },
693 b'(' => { let nn = if let Some(p) = dest.last_mut() { unsafe { p.as_mut().push(Value::A(Vec::new())); let Value::A(new) = &mut p.as_mut().last_mut().unwrap_unchecked() else { std::hint::unreachable_unchecked() }; NonNull::from(new)
698 }}
699 else {
700 NonNull::from(&mut abuf) };
702 dest.push(nn);
703 },
704 b')' => { if dest.pop().is_some() {
706 if dest.is_empty() { st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf)))); }
709 }
710 else {
711 synerr!(')', "Mismatched closing ')'");
712 }
713 },
714 b'x' => {
715 if let Some(top) = st.mstk.pop() {
716 let sec = st.mstk.pop();
717 match Utf8Iter::from_vals(&top, sec.as_deref()) {
718 Ok((mut stk, ret)) => {
719 if let Some(sec) = sec && ret { st.mstk.push(sec);
721 }
722
723 if mac.is_finished() && *count == Natural::ZERO { call.pop();
725 }
726
727 call.append(&mut stk);
728 continue 'mac;
729 },
730 Err(e) => {
731 if let Some(sec) = sec {st.mstk.push(sec);}
732 st.mstk.push(top);
733 synerr!('x', "{}", e);
734 }
735 }
736 }
737 else {
738 synerr!('x', "Expected 1 or 2 arguments, 0 given");
739 }
740 },
741 b'q' => {
742 let u = u8::wrapping_from(&Integer::rounding_from(rptr.unwrap_or_default(), RoundingMode::Down).0);
743 return if alt {
744 Ok(HardQuit(u))
745 }
746 else {
747 Ok(SoftQuit(u))
748 };
749 },
750 b'Q' => {
751 if let Some(va) = st.mstk.pop() {
752 match &*va {
753 Value::N(r) => {
754 if let Ok(u) = usize::try_from(r) {
755 call.truncate(call.len().saturating_sub(u));
756 if !dest.is_empty() { st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
758 dest.clear(); }
760 continue 'mac;
761 }
762 else {
763 let vs = va.to_string();
764 st.mstk.push(va);
765 valerr!('Q', "Cannot possibly break {} macros", vs);
766 }
767 },
768 _ => {
769 let ta = errors::TypeLabel::from(&*va);
770 st.mstk.push(va);
771 synerr!('Q', "Expected a number, {} given", ta);
772 }
773 }
774 }
775 else {
776 synerr!('Q', "Expected 1 argument, 0 given");
777 }
778 },
779 b'a' => { match mac.next() {
781 Some(b) if !matches!(byte_cmd(b), Space) => {
782 match b {
783 b'a' => {
784 todo!()
785 },
786 _ => {
787 synerr!('a', "Invalid array command 'a{}'", b as char);
788 }
789 }
790 },
791 Some(_) | None => {
792 synerr!('a', "Incomplete array command 'a'");
793 }
794 }
795 },
796 b'f' => { match mac.next() {
798 Some(b) if !matches!(byte_cmd(b), Space) => {
799 match b {
800 b'z' => { push!(Value::N(st.mstk.len().into()));
802 },
803 b'r' => { st.mstk.reverse();
805 },
806 b'R' => { if let Some(va) = st.mstk.pop() {
808 if let Value::N(r) = &*va {
809 match usize::try_from(r) {
810 Ok(0) => {}, Ok(u) => {
812 if let Some(from) = st.mstk.len().checked_sub(u) {
813 st.mstk[from..].reverse();
814 }
815 else {
816 st.mstk.push(va);
817 valerr!('f', "Can't reverse {} values, stack depth is {}", u, st.mstk.len() - 1);
818 }
819 }
820 Err(_) => {
821 let vs = va.to_string();
822 st.mstk.push(va);
823 valerr!('f', "Can't possibly reverse {} values", vs);
824 }
825 }
826 }
827 else {
828 let ta = errors::TypeLabel::from(&*va);
829 st.mstk.push(va);
830 synerr!('f', "Expected a number, {} given", ta);
831 }
832 }
833 else {
834 synerr!('f', "Expected 1 argument, 0 given");
835 }
836 },
837 b'f' => { let ri = if let Some(r) = rptr.take() {r}
839 else {
840 if matches!(mac.next().map(|b| {mac.back(); byte_cmd(b)}), None | Some(Space)) {
841 synerr!('f', "No register index");
842 alt = false;
843 continue 'cmd;
844 }
845 Rational::from(
846 match mac.try_next_char() {
847 Ok(c) => {c as u32},
848 Err(e) => {
849 *count = Natural::ZERO;
850 synerr!('\0', "Aborting invalid macro: {}", e);
851 break 'cmd;
852 }
853 }
854 )
855 };
856 let reg = st.regs.get_mut(&ri);
857 std::mem::swap(&mut st.mstk, &mut reg.v);
858 },
859 b'p' => { for v in &st.mstk {
861 let vs = v.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
862 if let Some(s) = &mut pbuf {
863 s.push_str(&vs);
864 s.push('\n');
865 }
866 else {
867 let out = &mut io.lock().unwrap().1;
868 writeln!(out, "{}", vs)?;
869 out.flush()?;
870 }
871 }
872 },
873 _ => {
874 synerr!('f', "Invalid stack command 'f{}'", b as char);
875 }
876 }
877 },
878 Some(_) | None => {
879 synerr!('f', "Incomplete stack command 'f'");
880 }
881 }
882 },
883 b'N' => {
884 match (st.mstk.pop(), alt) {
885 (Some(va), false) => { match &*va {
887 Value::N(r) => {
888 match Natural::try_from(r) {
889 Ok(n) => {
890 push!(Value::N(Rational::from(
891 malachite::natural::random::get_random_natural_less_than(&mut rng, &n)
892 )));
893 },
894 _ => {
895 st.mstk.push(va);
896 valerr!('N', "Limit must be a natural number");
897 }
898 }
899 },
900 _ => {
901 let t = errors::TypeLabel::from(&*va);
902 st.mstk.push(va);
903 synerr!('N', "Expected a number, {} given", t);
904 }
905 }
906 }
907 (Some(va), true) => { match &*va {
909 Value::N(r) => {
910 match Integer::try_from(r) {
911 Ok(Integer::NEGATIVE_ONE) => { rng = LazyCell::new(rng_os);
913 },
914 Ok(i) if Natural::convertible_from(&i) => { let n= unsafe { Natural::try_from(i).unwrap_unchecked() }; let mut bytes: Vec<u8> = PowerOf2DigitIterable::<u8>::power_of_2_digits(&n, 8).take(32).collect();
917 bytes.resize(32, 0);
918 *rng = rng_preset( unsafe { <[u8; 32]>::try_from(bytes).unwrap_unchecked() } );
919 },
920 _ => {
921 st.mstk.push(va);
922 valerr!('N', "Seed must be a natural number or `1");
923 }
924 }
925 },
926 _ => {
927 let t = errors::TypeLabel::from(&*va);
928 st.mstk.push(va);
929 synerr!('N', "Expected a number, {} given", t);
930 }
931 }
932 }
933 (None, _) => {
934 synerr!('N', "Expected 1 argument, 0 given");
935 }
936 }
937 },
938 b'w' => { if let Some(va) = st.mstk.pop() {
940 if let Value::N(r) = &*va {
941 if let Some(dur) = Natural::try_from(r).ok().and_then(|n| {
942 let (s, ns) = n.div_rem(Natural::const_from(1_000_000_000));
943 u64::try_from(&s).ok().map(|s| {
944 let ns = unsafe { u32::try_from(&ns).unwrap_unchecked() }; std::time::Duration::new(s, ns)
946 })
947 }) {
948 if let Some(rx) = kill {
949 match rx.recv_timeout(dur) {
950 Ok(()) => { return Ok(Finished);
952 },
953 Err(RecvTimeoutError::Timeout) => { },
956 Err(RecvTimeoutError::Disconnected) => { unreachable!()
958 }
959 }
960 }
961 else {
962 std::thread::sleep(dur); }
964 }
965 else {
966 let vs = va.to_string();
967 st.mstk.push(va);
968 valerr!('w', "Can't possibly wait {} ns", vs);
969 }
970 }
971 else {
972 let ta = crate::errors::TypeLabel::from(&*va);
973 st.mstk.push(va);
974 synerr!('w', "Expected a number, {} given", ta);
975 }
976 }
977 else {
978 synerr!('w', "Expected 1 argument, 0 given");
979 }
980 },
981 b'_' => { let mut word = Vec::new();
983 while let Some(b) = mac.next() {
984 if matches!(byte_cmd(b), Space) {
985 mac.back();
986 break;
987 }
988 else {
989 word.push(b);
990 }
991 }
992
993 match &word[..] { b"restrict" => {
995 restrict = true;
996 },
997 b"quiet" => {
998 ll = LogLevel::Quiet;
999 },
1000 b"error" => {
1001 ll = LogLevel::Normal;
1002 },
1003 b"debug" => {
1004 ll = LogLevel::Debug;
1005 },
1006 b"err" => {
1007 push!(Value::A(
1008 if let Some((n, c, s)) = elatch.take() {
1009 vec![
1010 Value::N(n.into()),
1011 Value::S(c.into()),
1012 Value::S(s)
1013 ]
1014 }
1015 else { vec![] }
1016 ));
1017 },
1018 b"th" => {
1019 push!(Value::S(th_name.clone()));
1020 },
1021 b"trim" => {
1022 st.trim();
1023 RE_CACHE.clear();
1024 },
1025 b"clhist" => {
1026 io.lock().unwrap().0.clear_history();
1027 },
1028 b"clpar" => {
1029 st.params = ParamStk::default();
1030 },
1031 b"clall" => {
1032 st.clear_vals();
1033 RE_CACHE.clear();
1034 },
1035 _ => {
1036 #[cfg(feature = "no_os")]
1037 {
1038 synerr!('_', "Invalid word command '{}'", string_or_bytes(&word));
1039 }
1040 #[cfg(not(feature = "no_os"))]
1041 {
1042 match (restrict, os::OS_CMDS.get(&word).copied()) {
1043 (false, Some(oscmd)) => {
1044 match oscmd(st) {
1045 Ok(mut v) => {
1046 append!(v);
1047 }
1048 Err(e) => {
1049 if let Some(se) = e.strip_suffix('!') {
1050 synerr!('_', "OS command '{}': {}", string_or_bytes(&word), se);
1051 }
1052 else {
1053 valerr!('_', "OS command '{}': {}", string_or_bytes(&word), e);
1054 }
1055 }
1056 }
1057 }
1058 (true, Some(_)) => {
1059 synerr!('_', "OS command '{}' is disabled (restricted mode)", string_or_bytes(&word));
1060 },
1061 _ => {
1062 synerr!('_', "Invalid word command '{}'", string_or_bytes(&word));
1063 }
1064 }
1065 }
1066 }
1067 }
1068 },
1069 _ => unreachable!()
1070 }
1071 },
1072 ExecR => {
1073 let ri = if let Some(r) = rptr.take() {r}
1074 else {
1075 if matches!(mac.next().map(|b| {mac.back(); byte_cmd(b)}), None | Some(Space)) {
1076 synerr!(b as char, "No register index");
1077 alt = false;
1078 continue 'cmd;
1079 }
1080 Rational::from(
1081 match mac.try_next_char() {
1082 Ok(c) => {c as u32},
1083 Err(e) => {
1084 *count = Natural::ZERO;
1085 synerr!('\0', "Aborting invalid macro: {}", e);
1086 break 'cmd;
1087 }
1088 }
1089 )
1090 };
1091 match b {
1092 b'Z' => { push!(Value::N(
1094 st.regs.try_get(&ri).map(|reg| reg.v.len().into()).unwrap_or_default()
1095 ));
1096 },
1097 b's' => {
1098 if let Some(va) = st.mstk.pop() {
1099 let reg = st.regs.get_mut(&ri);
1100 if let Some(rv) = reg.v.last_mut() {
1101 *rv = va;
1102 }
1103 else {
1104 reg.v.push(va);
1105 }
1106 }
1107 else {
1108 synerr!('s', "Stack is empty");
1109 }
1110 },
1111 b'S' => {
1112 if let Some(va) = st.mstk.pop() {
1113 st.regs.get_mut(&ri).v.push(va);
1114 }
1115 else {
1116 synerr!('S', "Stack is empty");
1117 }
1118 },
1119 b'l' => {
1120 if let Some(rv) = st.regs.try_get(&ri).and_then(|reg| reg.v.last()) {
1121 if let Some(p) = dest.last_mut() { unsafe {
1123 p.as_mut().push((**rv).clone()); }
1125 }
1126 else {
1127 st.mstk.push(Arc::clone(rv));
1128 }
1129 }
1130 else {
1131 synerr!('l', "Register {} is empty", reg_index_nice(&ri));
1132 }
1133 },
1134 b'L' => {
1135 if let Some(rv) = st.regs.try_get_mut(&ri).and_then(|reg| reg.v.pop()) {
1136 if let Some(p) = dest.last_mut() { unsafe {
1138 p.as_mut().push((*rv).clone()); }
1140 }
1141 else {
1142 st.mstk.push(Arc::clone(&rv));
1143 }
1144 }
1145 else {
1146 synerr!('L', "Register {} is empty", reg_index_nice(&ri));
1147 }
1148 },
1149 b'X' => {
1150 if let Some(true) = st.regs.try_get(&ri).map(|reg| reg.th.is_some()) {
1151 valerr!('X', "Register {} is already running a thread", reg_index_nice(&ri));
1152 }
1153 else if let Some(top) = st.mstk.pop() {
1154 let sec = st.mstk.pop();
1155 match Utf8Iter::from_vals(&top, sec.as_deref()) {
1156 Ok((stk, ret)) => {
1157 if let Some(sec) = sec && ret { st.mstk.push(sec);
1159 }
1160
1161 let (tx, rx) = std::sync::mpsc::channel::<()>();
1162 let tb = std::thread::Builder::new().name(format!("{th_name}{}: ", reg_index_nice(&ri)));
1163 let mut th_st = if alt { st.clone() } else { State::default() };
1164 let th_io = Arc::clone(&io);
1165
1166 match tb.spawn(move || {
1167 let mut th_res = (Vec::new(), Ok(Finished));
1168
1169 'all: for (th_start, th_count) in stk {
1170 for _ in malachite::natural::exhaustive::exhaustive_natural_range(Natural::ZERO, th_count) {
1171 match interpreter(&mut th_st, th_start.clone(), Arc::clone(&th_io), ll, Some(&rx), true) {
1172 Ok(Finished) => {continue;},
1173 Ok(er) => {
1174 th_res.1 = Ok(er);
1175 break 'all;
1176 },
1177 Err(e) => {
1178 th_res.1 = Err(e);
1179 break 'all;
1180 }
1181 }
1182 }
1183 }
1184
1185 th_res.0 = th_st.mstk;
1186 th_res
1187 }) {
1188 Ok(jh) => {
1189 st.regs.get_mut(&ri).th = Some((jh, tx));
1190 },
1191 Err(e) => {
1192 valerr!('X', "Can't spawn child thread: {}", e);
1193 }
1194 }
1195 },
1196 Err(e) => {
1197 if let Some(sec) = sec {st.mstk.push(sec);}
1198 st.mstk.push(top);
1199 synerr!('X', "{}", e);
1200 }
1201 }
1202 }
1203 else {
1204 synerr!('X', "Expected 1 or 2 arguments, 0 given");
1205 }
1206 },
1207 b'j' => {
1208 if let Some(reg) = st.regs.try_get_mut(&ri) && let Some((jh, tx)) = reg.th.take() {
1209 if alt {
1210 tx.send(()).unwrap_or_else(|_| panic!("Thread {} panicked, terminating!", reg_index_nice(&ri)));
1211 }
1212 match jh.join() {
1213 Ok(mut res) => {
1214 match res.1 {
1215 Err(e) => {
1216 valerr!('j', "IO error in thread {}: {}", reg_index_nice(&ri), e);
1217 },
1218 Ok(SoftQuit(c)) | Ok(HardQuit(c)) if c != 0 => {
1219 valerr!('j', "Thread {} exited with code {}", reg_index_nice(&ri), c);
1220 },
1221 _ => {}
1222 }
1223
1224 reg.v.append(&mut res.0);
1225 },
1226 Err(e) => {
1227 std::panic::resume_unwind(e);
1228 }
1229 }
1230 }
1231 else {
1232 valerr!('j', "Register {} is not running a thread", reg_index_nice(&ri));
1233 }
1234 },
1235 b'J' => {
1236 if let Some(Some((jh, _))) = st.regs.try_get(&ri).map(|reg| ®.th) {
1237 let mut bz = BitVec::new();
1238 bz.push(jh.is_finished());
1239 push!(Value::B(bz));
1240 }
1241 else {
1242 valerr!('J', "Register {} is not running a thread", reg_index_nice(&ri));
1243 }
1244 },
1245 _ => unreachable!()
1246 }
1247 },
1248 Lit => {
1249 match b {
1250 b'T' | b'F' => { let mut bits = BitVec::new();
1252 bits.push(b == b'T');
1253 while let Some(b) = mac.next() {
1254 match b {
1255 b'T' => {bits.push(true);},
1256 b'F' => {bits.push(false);},
1257 _ => {
1258 mac.back();
1259 break;
1260 }
1261 }
1262 }
1263 push!(Value::B(bits));
1264 },
1265 b'\'' | b'0'..=b'9' | b'.' | b'@' => { let mut ipart = Vec::new();
1267 let mut fpart = Vec::new();
1268 let mut rpart = Vec::new();
1269 let mut get_epart = true;
1270 let mut exp = None;
1271 let mut discard = false;
1272 let mut ibase = st.params.get_i().clone();
1273
1274 match (b == b'\'', ibase > Natural::const_from(36)) {
1275 (false, high_base) => { mac.back();
1277 ibase = if high_base {Natural::const_from(10)} else {ibase}; while let Some(ib) = mac.next() { let id = ib.wrapping_sub(0x30);
1280 match id {
1281 0..=9 if id < ibase => {ipart.push(Natural::from(id));},
1282 0..=9 => {
1283 synerr!('\'', "Digit {} is too high for base {}", id, ibase);
1284 discard = true;
1285 },
1286 _ => {
1287 mac.back();
1288 break;
1289 }
1290 }
1291 }
1292 match mac.next() {
1293 Some(b'.') => { let mut recur = false; while let Some(fb) = mac.next() {
1296 let fd = fb.wrapping_sub(0x30);
1297 match fd {
1298 0x30 if !recur => {recur = true;}, 0..=9 if !recur && fd < ibase => {fpart.push(Natural::from(fd));},
1300 0..=9 if recur && fd < ibase => {rpart.push(Natural::from(fd));},
1301 0..=9 => {
1302 synerr!('\'', "Digit {} is too high for base {}", fd, ibase);
1303 discard = true;
1304 },
1305 _ => {
1306 mac.back();
1307 break;
1308 }
1309 }
1310 }
1311 },
1312 Some(_) => {mac.back();},
1313 None => {}
1314 }
1315 }
1316 (true, false) => { while let Some(ib) = mac.next() { if let Some(id) = mixed_ascii_to_digit(ib) {
1319 if id < ibase {ipart.push(Natural::from(id));}
1320 else {
1321 synerr!('\'', "Digit {} is too high for base {}", id, ibase);
1322 discard = true;
1323 }
1324 }
1325 else {
1326 mac.back();
1327 break;
1328 }
1329 }
1330 match mac.next() {
1331 Some(b'.') => { let mut recur = false; while let Some(fb) = mac.next() {
1334 if let Some(fd) = mixed_ascii_to_digit(fb) {
1335 if fd < ibase {
1336 if !recur {fpart.push(Natural::from(fd));}
1337 else {rpart.push(Natural::from(fd));}
1338 }
1339 else {
1340 synerr!('\'', "Digit {} is too high for base {}", fd, ibase);
1341 discard = true;
1342 }
1343 }
1344 else if !recur && fb == b'`' {recur = true;}
1345 else {
1346 mac.back();
1347 break;
1348 }
1349 }
1350 },
1351 Some(_) => {mac.back();},
1352 None => {}
1353 }
1354 },
1355 (true, true) => { get_epart = false;
1357 let ns= mac.by_ref().take_while(|b| *b != b'\'').collect::<Vec<u8>>();
1358 if ns.is_empty() {
1359 synerr!('\'', "Empty any-base number");
1360 alt = false;
1361 continue 'cmd;
1362 }
1363 for nc in ns.iter() {
1364 match nc {
1365 b' ' | b'.' | b'0'..=b'9' | b'@' | b'`' => {} wrong => {
1367 synerr!('\'', "Invalid character in any-base number: {}", string_or_bytes(&[*wrong]));
1368 alt = false;
1369 continue 'cmd;
1370 }
1371 }
1372 }
1373 let mut ms = Vec::new();
1374 match ns.split(|b| *b == b'@').collect::<Vec<&[u8]>>()[..] {
1375 [mpart] => { ms = mpart.to_vec();
1377 },
1378 [mpart, epart] => { ms = mpart.to_vec();
1380 let mut es = epart.to_vec();
1381 if let Some(first) = es.first_mut() && *first == b'`' { *first = b'-'; }
1382 match String::from_utf8(es) {
1383 Ok(es) => {
1384 match es.parse::<i64>() {
1385 Ok(i) => { exp = Some(i); },
1386 Err(e) => {
1387 use std::num::IntErrorKind::*;
1388 match e.kind() {
1389 Empty => { exp = Some(0); },
1390 InvalidDigit => {
1391 valerr!('\'', "Invalid exponent: {}", es);
1392 alt = false;
1393 continue 'cmd;
1394 },
1395 PosOverflow | NegOverflow => {
1396 valerr!('\'', "Exponent {} is unrepresentable", es);
1397 alt = false;
1398 continue 'cmd;
1399 },
1400 _ => { unreachable!() }
1401 }
1402 }
1403 }
1404 },
1405 _ => { unreachable!() }
1406 }
1407 },
1408 ref v => {
1409 synerr!('\'', "{} exponent signs (@) in any-base number", v.len() - 1);
1410 drop(ms);
1411 alt = false;
1412 continue 'cmd;
1413 }
1414 }
1415 let mut is = Vec::new();
1416 let mut frs = Vec::new();
1417 match ms.split(|b| *b == b'.').collect::<Vec<&[u8]>>()[..] {
1418 [ipart] => {
1419 is = ipart.to_vec();
1420 },
1421 [ipart, fpart] => {
1422 is = ipart.to_vec();
1423 frs = fpart.to_vec();
1424 },
1425 ref v => {
1426 synerr!('\'', "{} fractional points (.) in any-base number", v.len() - 1);
1427 drop(is);
1428 alt = false;
1429 continue 'cmd;
1430 }
1431 }
1432 if is.contains(&b'`') {
1433 synerr!('\'', "Negative sign (`) inside any-base number");
1434 alt = false;
1435 continue 'cmd;
1436 }
1437 let mut fs = Vec::new();
1438 let mut rs = Vec::new();
1439 match frs.split(|b| *b == b'`').collect::<Vec<&[u8]>>()[..] {
1440 [fpart] => {
1441 fs = fpart.to_vec();
1442 },
1443 [fpart, rpart] => {
1444 fs = fpart.to_vec();
1445 rs = rpart.to_vec();
1446 },
1447 ref v => {
1448 synerr!('\'', "{} recurring marks (`) in any-base number", v.len() - 1);
1449 drop(fs);
1450 alt = false;
1451 continue 'cmd;
1452 }
1453 }
1454 if !is.is_empty() { for id in is.split(|b| *b == b' ') {
1455 let id = str::from_utf8(id).unwrap();
1456 ipart.push(Natural::from_str(id).unwrap());
1457 }}
1458 if !fs.is_empty() { for fd in fs.split(|b| *b == b' ') {
1459 let fd = str::from_utf8(fd).unwrap();
1460 fpart.push(Natural::from_str(fd).unwrap());
1461 }}
1462 if !rs.is_empty() { for rd in rs.split(|b| *b == b' ') {
1463 let rd = str::from_utf8(rd).unwrap();
1464 rpart.push(Natural::from_str(rd).unwrap());
1465 }}
1466 for d in ipart.iter().chain(fpart.iter()).chain(rpart.iter()) {
1467 if *d >= ibase {
1468 synerr!('\'', "Digit {} is too high for base {}", d, ibase);
1469 alt = false;
1470 continue 'cmd;
1471 }
1472 }
1473 }
1474 }
1475
1476 let m_empty = ipart.is_empty() && fpart.is_empty() && rpart.is_empty(); let mut r;
1478 if m_empty {
1479 r = Rational::ZERO;
1480 }
1481 else {
1482 ipart.reverse(); r = Rational::from_digits(&ibase, ipart, RationalSequence::from_vecs(fpart, rpart));
1484 if alt {r.neg_assign();} }
1486
1487 if get_epart {
1488 match mac.next() {
1489 Some(b'@') => { let mut es = String::new();
1491 let mut eneg = false; while let Some(eb) = mac.next() {
1493 match eb {
1494 b'`' if !eneg => { es.push('-'); }
1495 b'0'..=b'9' => { es.push(eb as char); }
1496 _ => {
1497 mac.back();
1498 break;
1499 }
1500 }
1501 eneg = true; }
1503 if es.is_empty() { es.push('0'); }
1504 if m_empty { r = Rational::ONE; } if let Ok(i) = es.parse::<i64>() {
1506 r *= Rational::from(st.params.get_i()).pow(i); }
1508 else {
1509 valerr!('\'', "Exponent {} is unrepresentable", es);
1510 discard = true;
1511 }
1512 }
1513 Some(_) => { mac.back(); }
1514 None => {}
1515 }
1516 }
1517 else if let Some(i) = exp {
1518 if m_empty { r = Rational::ONE; } r *= Rational::from(ibase).pow(i); }
1521
1522 if !discard {
1523 push!(Value::N(r));
1524 }
1525 },
1526 b'[' => { let mut bytes = Vec::new();
1528 let mut discard = false;
1529 let mut nest = 1usize;
1530 while let Some(b) = mac.next() {
1531 match b {
1532 b'[' => {
1533 nest = unsafe { nest.unchecked_add(1) };
1534 bytes.push(b'[');
1535 },
1536 b']' => {
1537 nest = unsafe { nest.unchecked_sub(1) };
1538 if nest == 0 {
1539 break;
1540 }
1541 else {
1542 bytes.push(b']');
1543 }
1544 },
1545 b'\\' => { match mac.next() {
1547 Some(b'a') => {bytes.push(0x07);}, Some(b'b') => {bytes.push(0x08);}, Some(b't') => {bytes.push(0x09);}, Some(b'n') => {bytes.push(0x0A);}, Some(b'v') => {bytes.push(0x0B);}, Some(b'f') => {bytes.push(0x0C);}, Some(b'r') => {bytes.push(0x0D);}, Some(b'e') => {bytes.push(0x1B);}, Some(b'[') => {bytes.push(b'[');}, Some(b']') => {bytes.push(b']');}, Some(b'\\') => {bytes.push(b'\\');}, Some(b0) => { if let Some(high) = upper_hex_to_nibble(b0) { if let Some(b1) = mac.next() {
1561 if let Some(low) = upper_hex_to_nibble(b1) {
1562 bytes.push(high << 4 | low);
1563 }
1564 else {
1565 synerr!('[', "Invalid byte escape: \\{}{}", b0 as char, b1 as char);
1566 discard = true;
1567 }
1568 }
1569 else {
1570 synerr!('[', "Incomplete byte escape: \\{}", b0 as char);
1571 discard = true;
1572 }
1573 }
1574 else { mac.back();
1576 match mac.try_next_char() {
1577 Ok(c) => {
1578 synerr!('[', "Invalid character escape: \\{} (U+{:04X})", c, c as u32);
1579 discard = true;
1580 },
1581 Err(e) => {
1582 *count = Natural::ZERO;
1583 synerr!('\0', "Aborting invalid macro: {}", e);
1584 break 'cmd;
1585 }
1586 }
1587 }
1588 },
1589 None => {
1590 synerr!('[', "Incomplete character escape: \\");
1591 discard = true;
1592 }
1593 }
1594 },
1595 _ => {
1596 bytes.push(b);
1597 }
1598 }
1599 }
1600 if !discard {
1601 match String::try_from(Utf8Iter::from(bytes)) {
1602 Ok(s) => {
1603 push!(Value::S(s));
1604 },
1605 Err(e) => {
1606 synerr!('[', "Invalid string: {}", e);
1607 }
1608 }
1609 }
1610 },
1611 _ => unreachable!()
1612 }
1613 },
1614 Space if b == b'#' => { mac.find(|b| *b == b'\n');
1616 },
1617 Space => {
1618 },
1620 Wrong => {
1621 mac.back();
1622 match mac.try_next_char() {
1623 Ok(c) => {
1624 synerr!(c, "Invalid command: {} (U+{:04X})", c, c as u32);
1625 },
1626 Err(e) => {
1627 *count = Natural::ZERO;
1628 synerr!('\0', "Aborting invalid macro: {}", e);
1629 break 'cmd;
1630 }
1631 }
1632 }
1633 }
1634
1635 alt = false; } if !dest.is_empty() { st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
1640 dest.clear(); }
1642
1643 if *count == Natural::ZERO { call.pop();
1645 }
1646 else { mac.rewind();
1648 }
1649 } Ok(Finished)
1652}