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::io::{Write, BufRead, ErrorKind};
20use std::panic::catch_unwind;
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, RoundingFrom, WrappingFrom};
30use malachite::base::num::random::RandomPrimitiveInts;
31use malachite::base::rational_sequences::RationalSequence;
32use malachite::base::rounding_modes::RoundingMode;
33use crate::errors::TypeLabel;
34
35
36pub const STATE_FILE_HEADER: [u8;20] = *b"# ADC state file v1\n";
38
39struct LineEditor(Interface<DefaultTerminal>);
40impl Default for LineEditor {
41 fn default() -> Self {
42 use linefeed::Signal::*;
43 let iface = Interface::new("").unwrap();
44 iface.set_report_signal(Break, true);
46 iface.set_report_signal(Interrupt, true);
47 iface.set_report_signal(Quit, true);
48 Self(iface)
49 }
50}
51
52pub trait ReadLine {
56 fn read_line(&mut self) -> std::io::Result<String>;
60
61 fn clear_history(&mut self);
63}
64impl<T: BufRead> ReadLine for T {
65 fn read_line(&mut self) -> std::io::Result<String> {
66 let mut buf = String::new();
67 self.read_line(&mut buf)?;
68 Ok(buf)
69 }
70
71 fn clear_history(&mut self) {
72 }
74}
75impl ReadLine for LineEditor {
76 fn read_line(&mut self) -> std::io::Result<String> {
77 use linefeed::{ReadResult, Signal};
78 match self.0.read_line() {
79 Ok(ReadResult::Input(s)) => {
80 self.0.add_history_unique(s.clone());
81 Ok(s)
82 },
83 Ok(ReadResult::Eof) => {Err(ErrorKind::UnexpectedEof.into())},
84 Ok(ReadResult::Signal(sig)) => {
85 self.0.cancel_read_line()?;
86 match sig {
87 Signal::Break | Signal::Interrupt | Signal::Quit => {Err(ErrorKind::Interrupted.into())},
88 Signal::Continue => {Err(std::io::Error::other("Unhandled SIGCONT"))},
89 Signal::Suspend => {Err(std::io::Error::other("Unhandled SIGTSTP"))},
90 Signal::Resize => {Err(std::io::Error::other("Unhandled window resize"))},
91 }
92 },
93 Err(e) => {Err(e)}
94 }
95 }
96
97 fn clear_history(&mut self) {
98 self.0.clear_history();
99 }
100}
101
102pub struct IOStreams (
104 pub Box<dyn ReadLine + Send>,
106 pub Box<dyn Write + Send>,
108 pub Box<dyn Write + Send>
110);
111impl IOStreams {
112 pub fn empty() -> Self {
114 Self (
115 Box::new(std::io::empty()),
116 Box::new(std::io::empty()),
117 Box::new(std::io::empty())
118 )
119 }
120
121 pub fn process() -> Self {
123 Self (
124 Box::new(LineEditor::default()),
125 Box::new(std::io::stdout()),
126 Box::new(std::io::stderr())
127 )
128 }
129}
130
131lazy_static::lazy_static! {
132 pub(crate) static ref RE_CACHE: RegexCache = RegexCache::default();
133}
134
135fn rng_preset(bytes: [u8; 32]) -> RandomPrimitiveInts<u64> {
136 malachite::base::num::random::random_primitive_ints(malachite::base::random::Seed::from_bytes(bytes))
137}
138
139fn rng_os() -> RandomPrimitiveInts<u64> {
140 let mut bytes = [0u8; 32];
141 getrandom::fill(&mut bytes).unwrap();
142 rng_preset(bytes)
143}
144
145#[derive(Default, Clone, Copy)]
146enum Command {
147 Fn1(fns::Mon),
149
150 Fn2(fns::Dya),
152
153 Fn3(fns::Tri),
155
156 Cmd(cmds::Cmd),
158
159 Exec,
161
162 ExecR,
164
165 Lit,
167
168 Space,
170
171 #[default] Wrong,
173}
174
175const CMDS: [Command; 256] = {
177 use Command::*;
178 use fns::*;
179 use cmds::*;
180 [
181 Space, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Space, Space, Space, Space, Space, Wrong, Wrong,
183
184 Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong, Wrong,
186
187 Space, Fn1(neg), Exec, Space, Wrong, Fn2(modu), Wrong, Lit, Exec, Exec, Fn2(mul), Fn2(add), Wrong, Fn2(sub), Lit, Fn2(div),
189
190 Lit, Lit, Lit, Lit, Lit, Lit, Lit, Lit, Lit, Lit, Exec, Wrong, Fn2(lt), Fn2(eq), Fn2(gt), Exec,
192
193 Lit, Wrong, Wrong, Cmd(cln), Exec, Wrong, Lit, Fn2(logb), Wrong, Cmd(gi), ExecR, Cmd(gk), ExecR, Cmd(gm), Exec, Cmd(go),
195
196 Exec, Exec, Exec, ExecR, Lit, Wrong, Fn2(root), Wrong, ExecR, Wrong, ExecR, Lit, Wrong, Wrong, Fn2(pow), Exec,
198
199 Exec, Exec, Wrong, Cmd(cls), Exec, Wrong, Exec, Fn1(log), Wrong, Cmd(si), ExecR, Cmd(sk), ExecR, Cmd(sm), Fn1(fac), Cmd(so),
201
202 Exec, Exec, Cmd(rev), ExecR, Fn2(trig), Wrong, Fn1(sqrt), Exec, Exec, Wrong, Fn1(disc), Cmd(cbo), Fn3(bar), Cmd(cbc), Fn2(euc), Wrong,
204
205 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,
207 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,
208 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,
209 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
210 ]
211};
212
213fn byte_cmd(b: u8) -> Command {
214 unsafe { *CMDS.get_unchecked(b as usize)
216 }
217}
218
219fn string_or_bytes(v: &[u8]) -> String {
220 str::from_utf8(v).map(|s| s.to_owned()).unwrap_or_else(|_| {
221 let mut res = String::from("(not UTF-8: [");
222 for b in v {
223 res += &format!("\\{b:02X}");
224 }
225 res += "])";
226 res
227 })
228}
229
230fn upper_hex_to_nibble(b: u8) -> Option<u8> {
231 match b {
232 b'0'..=b'9' => Some(unsafe{b.unchecked_sub(0x30)}), b'A'..=b'F' => Some(unsafe{b.unchecked_sub(0x37)}),
234 _ => None
235 }
236}
237
238fn mixed_ascii_to_digit(b: u8) -> Option<u8> {
239 match b {
240 b'0'..=b'9' => Some(unsafe{b.unchecked_sub(0x30)}), b'A'..=b'Z' => Some(unsafe{b.unchecked_sub(0x37)}),
242 b'a'..=b'z' => Some(unsafe{b.unchecked_sub(0x57)}),
243 _ => None
244 }
245}
246
247#[derive(Debug, PartialEq, Eq, Clone, Copy)]
249pub enum LogLevel {
250 Normal,
252 Debug,
254 Quiet
256}
257
258#[derive(Clone, Copy, Debug, PartialEq)]
260#[must_use] pub enum ExecResult {
261 Finished,
263
264 SoftQuit(u8),
266
267 HardQuit(u8),
269
270 Killed
272}
273
274pub fn interpreter_no_os(
276 st: &mut State,
277 start: Utf8Iter,
278 io: Arc<Mutex<IOStreams>>,
279 ll: LogLevel,
280 kill: Option<&Receiver<()>>,
281) -> std::io::Result<ExecResult>
282{
283 unsafe { interpreter(st, start, io, ll, kill, true) }
285}
286
287pub unsafe fn interpreter(
313 st: &mut State,
314 start: Utf8Iter,
315 io: Arc<Mutex<IOStreams>>,
316 mut ll: LogLevel,
317 kill: Option<&Receiver<()>>,
318 #[cfg_attr(feature = "no_os", allow(unused_variables))]
319 mut restrict: bool
320) -> std::io::Result<ExecResult>
321{
322 use ExecResult::*;
323
324 let th_name = if kill.is_some() { #[cfg_attr(feature = "no_os", allow(unused_assignments))] { restrict = true; } std::thread::current().name().unwrap().to_owned()
327 }
328 else {
329 String::new()
330 };
331
332 let mut pbuf: Option<String> = None; let mut elatch: Option<(Natural, char, String)> = None;
335
336 macro_rules! synerr {
337 ($c:expr, $s:expr) => {
338 if ll != LogLevel::Quiet {
339 let err = &mut io.lock().unwrap().2;
340 writeln!(err, "! {th_name}{}: {}", $c, $s)?;
341 err.flush()?;
342 }
344 elatch = Some((Natural::ZERO, $c, $s.into()));
345 };
346 ($c:expr, $f:literal, $($s:expr),*) => {
347 let s = format!($f, $($s),*);
348 if ll != LogLevel::Quiet {
349 let err = &mut io.lock().unwrap().2;
350 writeln!(err, "! {th_name}{}: {}", $c, s)?;
351 err.flush()?;
352 }
354 elatch = Some((Natural::ZERO, $c, s));
355 };
356 }
357
358 macro_rules! valerr {
359 ($c:expr, $s:expr) => {
360 if ll != LogLevel::Quiet {
361 let err = &mut io.lock().unwrap().2;
362 writeln!(err, "? {th_name}{}: {}", $c, $s)?;
363 err.flush()?;
364 }
366 elatch = Some((Natural::ZERO, $c, $s.into()));
367 };
368 ($c:expr, $f:literal, $($s:expr),*) => {
369 let s = format!($f, $($s),*);
370 if ll != LogLevel::Quiet {
371 let err = &mut io.lock().unwrap().2;
372 writeln!(err, "? {th_name}{}: {}", $c, s)?;
373 err.flush()?;
374 }
376 elatch = Some((Natural::ZERO, $c, s));
377 };
378 }
379
380 macro_rules! debug {
381 ($s:expr) => {
382 if ll == LogLevel::Debug {
383 let err = &mut io.lock().unwrap().2;
384 writeln!(err, "\tDEBUG: {th_name}{}", $s)?;
385 err.flush()?;
386 }
388 };
389 ($f:literal, $($s:expr),*) => {
390 if ll == LogLevel::Debug {
391 let err = &mut io.lock().unwrap().2;
392 writeln!(err, "\tDEBUG: {th_name}{}", format!($f, $($s),*))?;
393 err.flush()?;
394 }
396 };
397 }
398
399 let mut rptr: Option<Rational> = None; let mut rng: Option<RandomPrimitiveInts<u64>> = None;
402
403 let mut call: Vec<(Utf8Iter, Natural)> = vec![(start, Natural::const_from(1))];
404
405 'mac: while let Some((mac, count)) = call.last_mut() { *count -= Natural::ONE;
407 let mut alt = false;
408
409 let mut abuf: Vec<Value> = Vec::new(); let mut dest: Vec<NonNull<Vec<Value>>> = Vec::new(); macro_rules! push {
413 ($v:expr) => {
414 if let Some(p) = dest.last_mut() {
415 unsafe {
416 p.as_mut().push($v); }
418 }
419 else {
420 st.mstk.push(Arc::new($v));
421 }
422 };
423 }
424 macro_rules! append {
426 ($v:expr) => {
427 if let Some(p) = dest.last_mut() {
428 unsafe {
429 p.as_mut().append(&mut $v); }
431 }
432 else {
433 for val in $v {
434 st.mstk.push(Arc::new(val));
435 }
436 }
437 };
438 }
439
440 'cmd: while let Some(b) = mac.next() { if let Some(rx) = kill { match rx.try_recv() {
443 Ok(()) => { #[expect(unused_assignments)]
445 for s in st.regs.end_threads(true) { valerr!('j', s);
447 }
448 return Ok(Killed);
449 },
450 Err(TryRecvError::Empty) => { },
453 Err(TryRecvError::Disconnected) => { unreachable!()
455 }
456 }
457 }
458
459 if let Some(e) = &mut elatch { e.0 += Natural::ONE;
461 }
462
463 use Command::*;
464 match byte_cmd(b) {
465 Fn1(mon) => {
466 if let Some(va) = st.mstk.pop() {
467 debug!("Monadic {}{} with {}", if alt {"alt-"} else {""}, b as char, TypeLabel::from(&*va));
468 match catch_unwind(|| fns::exec1(mon, &va, alt)) {
469 Ok(Ok(vz)) => {
470 push!(vz);
471 },
472 Ok(Err(e)) => {
473 st.mstk.push(va);
474 valerr!(b as char, e.to_string());
475 },
476 Err(cause) => {
477 st.mstk.push(va);
478 valerr!(b as char, "Caught function panic: {:?}", cause);
479 }
480 }
481 }
482 else {
483 synerr!(b as char, "Expected 1 argument, 0 given");
484 }
485 },
486 Fn2(dya) => {
487 if let Some(vb) = st.mstk.pop() {
488 if let Some(va) = st.mstk.pop() {
489 debug!("Dyadic {}{} with ({}, {})", if alt {"alt-"} else {""}, b as char, TypeLabel::from(&*va), TypeLabel::from(&*vb));
490 match catch_unwind(|| fns::exec2(dya, &va, &vb, alt)) {
491 Ok(Ok(vz)) => {
492 push!(vz);
493 },
494 Ok(Err(e)) => {
495 st.mstk.push(va);
496 st.mstk.push(vb);
497 valerr!(b as char, e.to_string());
498 },
499 Err(cause) => {
500 st.mstk.push(va);
501 st.mstk.push(vb);
502 valerr!(b as char, "Caught function panic: {:?}", cause);
503 }
504 }
505 }
506 else {
507 st.mstk.push(vb);
508 synerr!(b as char, "Expected 2 arguments, 1 given");
509 }
510 }
511 else {
512 synerr!(b as char, "Expected 2 arguments, 0 given");
513 }
514 },
515 Fn3(tri) => {
516 if let Some(vc) = st.mstk.pop() {
517 if let Some(vb) = st.mstk.pop() {
518 if let Some(va) = st.mstk.pop() {
519 debug!("Triadic {}{} with ({}, {}, {})", if alt {"alt-"} else {""}, b as char, TypeLabel::from(&*va), TypeLabel::from(&*vb), TypeLabel::from(&*vc));
520 match catch_unwind(|| fns::exec3(tri, &va, &vb, &vc, alt)) {
521 Ok(Ok(vz)) => {
522 push!(vz);
523 },
524 Ok(Err(e)) => {
525 st.mstk.push(va);
526 st.mstk.push(vb);
527 st.mstk.push(vc);
528 valerr!(b as char, e.to_string());
529 },
530 Err(cause) => {
531 st.mstk.push(va);
532 st.mstk.push(vb);
533 st.mstk.push(vc);
534 valerr!(b as char, "Caught function panic: {:?}", cause);
535 }
536 }
537 }
538 else {
539 st.mstk.push(vb);
540 st.mstk.push(vc);
541 synerr!(b as char, "Expected 3 arguments, 2 given");
542 }
543 }
544 else {
545 st.mstk.push(vc);
546 synerr!(b as char, "Expected 3 arguments, 1 given");
547 }
548 }
549 else {
550 synerr!(b as char, "Expected 3 arguments, 0 given");
551 }
552 },
553 Cmd(cmd) => {
554 debug!("Impure command {}", b as char);
555 match cmd(st) {
556 Ok(mut v) => {
557 append!(v);
558 }
559 Err(e) => {
560 if let Some(se) = e.strip_suffix('!') {
561 synerr!(b as char, se);
562 }
563 else {
564 valerr!(b as char, e);
565 }
566 }
567 }
568 },
569 Exec => {
570 debug!("Command {}{}", if alt {"alt-"} else {""}, b as char);
571 match b {
572 b'`' => { alt = true;
574 continue 'cmd; },
576 b':' if !alt => { if let Some(va) = st.mstk.pop() {
578 if let Value::N(r) = &*va {
579 rptr = Some(r.clone());
580 }
581 else {
582 let ta = TypeLabel::from(&*va);
583 st.mstk.push(va);
584 synerr!(':', "Expected a number, {} given", ta);
585 }
586 }
587 else {
588 synerr!(':', "Expected 1 argument, 0 given");
589 }
590 },
591 b':' if alt => { push!(
593 if let Some(ri) = rptr.take() {
594 Value::N(ri)
595 }
596 else {
597 Value::A(vec![])
598 }
599 );
600 },
601 b'd' => {
602 if let Some(v) = st.mstk.last() {
603 if let Some(p) = dest.last_mut() { unsafe {
605 p.as_mut().push((**v).clone()); }
607 }
608 else {
609 st.mstk.push(Arc::clone(v));
610 }
611 }
612 else {
613 synerr!('d', "Stack is empty");
614 }
615 },
616 b'D' => {
617 if let Some(va) = st.mstk.pop() {
618 if let Value::N(r) = &*va {
619 match usize::try_from(r) {
620 Ok(0) => {}, Ok(u) => {
622 if let Some(from) = st.mstk.len().checked_sub(u) {
623 if let Some(p) = dest.last_mut() { for v in &st.mstk[from..] {
625 unsafe {
626 p.as_mut().push((**v).clone()); }
628 }
629 }
630 else {
631 st.mstk.extend_from_within(from..);
632 }
633 }
634 else {
635 st.mstk.push(va);
636 valerr!('D', "Can't duplicate {} values, stack depth is {}", u, st.mstk.len() - 1);
637 }
638 }
639 Err(_) => {
640 let vs = va.to_string();
641 st.mstk.push(va);
642 valerr!('D', "Can't possibly duplicate {} values", vs);
643 }
644 }
645 }
646 else {
647 let ta = TypeLabel::from(&*va);
648 st.mstk.push(va);
649 synerr!('D', "Expected a number, {} given", ta);
650 }
651 }
652 else {
653 synerr!('D', "Expected 1 argument, 0 given");
654 }
655 },
656 b'R' => { if let Some(va) = st.mstk.pop() {
658 if let Value::N(r) = &*va {
659 match usize::try_from(r) {
660 Ok(0) => {}, Ok(u) => {
662 if let Some(from) = st.mstk.len().checked_sub(u) {
663 if alt {st.mstk[from..].rotate_left(1);}
664 else {st.mstk[from..].rotate_right(1);}
665 }
666 else {
667 st.mstk.push(va);
668 valerr!('R', "Can't rotate {} values, stack depth is {}", u, st.mstk.len() - 1);
669 }
670 }
671 Err(_) => {
672 let vs = va.to_string();
673 st.mstk.push(va);
674 valerr!('R', "Can't possibly rotate {} values", vs);
675 }
676 }
677 }
678 else {
679 let ta = TypeLabel::from(&*va);
680 st.mstk.push(va);
681 synerr!('R', "Expected a number, {} given", ta);
682 }
683 }
684 else {
685 synerr!('R', "Expected 1 argument, 0 given");
686 }
687 },
688 b'?' => { let res = {
690 let inp = &mut io.lock().unwrap().0;
691 inp.read_line()
692 };
694 match res {
695 Ok(s) => {
696 push!(Value::S(s));
697 },
698 Err(e) => {
699 match e.kind() {
700 ErrorKind::Interrupted => {
701 valerr!('?', "Interrupted");
702 },
703 ErrorKind::UnexpectedEof => {
704 push!(Value::S(String::new()));
705 },
706 _ => {
707 return Err(e);
708 }
709 }
710 }
711 }
712 },
713 b'p' => { if let Some(va) = st.mstk.pop() {
715 let vs = va.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
716 if let Some(s) = &mut pbuf {
717 s.push_str(&vs);
718 s.push('\n');
719 }
720 else {
721 let out = &mut io.lock().unwrap().1;
722 writeln!(out, "{}", vs)?;
723 out.flush()?;
724 }
726 }
727 else {
728 synerr!('p', "Expected 1 argument, 0 given");
729 }
730 },
731 b'P' => { if let Some(va) = st.mstk.pop() {
733 let vs = va.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
734 if let Some(s) = &mut pbuf {
735 s.push_str(&vs);
736 }
737 else {
738 let out = &mut io.lock().unwrap().1;
739 write!(out, "{}", vs)?;
740 out.flush()?;
741 }
743 }
744 else {
745 synerr!('P', "Expected 1 argument, 0 given");
746 }
747 },
748 b'"' => { if let Some(s) = pbuf.take() { push!(Value::S(s));
751 }
752 else { pbuf = Some(String::new());
754 }
755 },
756 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)
761 }}
762 else {
763 NonNull::from(&mut abuf) };
765 dest.push(nn);
766 },
767 b')' => { if dest.pop().is_some() {
769 if dest.is_empty() { st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf)))); }
772 }
773 else {
774 synerr!(')', "Mismatched closing ')'");
775 }
776 },
777 b'x' => {
778 if let Some(top) = st.mstk.pop() {
779 let sec = st.mstk.pop();
780 match Utf8Iter::from_vals(&top, sec.as_deref()) {
781 Ok((mut stk, ret)) => {
782 if let Some(sec) = sec && ret { st.mstk.push(sec);
784 }
785
786 if mac.is_finished() && *count == Natural::ZERO { call.pop();
788 }
789
790 call.append(&mut stk);
791 continue 'mac;
792 },
793 Err(e) => {
794 if let Some(sec) = sec {st.mstk.push(sec);}
795 st.mstk.push(top);
796 synerr!('x', "{}", e);
797 }
798 }
799 }
800 else {
801 synerr!('x', "Expected 1 or 2 arguments, 0 given");
802 }
803 },
804 b'q' => {
805 let u = u8::wrapping_from(&Integer::rounding_from(rptr.unwrap_or_default(), RoundingMode::Down).0);
806 return if alt {
807 Ok(HardQuit(u))
808 }
809 else {
810 Ok(SoftQuit(u))
811 };
812 },
813 b'Q' => {
814 if let Some(va) = st.mstk.pop() {
815 match &*va {
816 Value::N(r) => {
817 if let Ok(u) = usize::try_from(r) {
818 call.truncate(call.len().saturating_sub(u));
819 if !dest.is_empty() { st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
821 dest.clear(); }
823 continue 'mac;
824 }
825 else {
826 let vs = va.to_string();
827 st.mstk.push(va);
828 valerr!('Q', "Cannot possibly break {} macros", vs);
829 }
830 },
831 _ => {
832 let ta = TypeLabel::from(&*va);
833 st.mstk.push(va);
834 synerr!('Q', "Expected a number, {} given", ta);
835 }
836 }
837 }
838 else {
839 synerr!('Q', "Expected 1 argument, 0 given");
840 }
841 },
842 b'a' => { match mac.next() {
844 Some(b) if !matches!(byte_cmd(b), Space) => {
845 match b {
846 b'a' => {
847 todo!()
848 },
849 _ => {
850 synerr!('a', "Invalid array command 'a{}'", b as char);
851 }
852 }
853 },
854 Some(_) | None => {
855 synerr!('a', "Incomplete array command 'a'");
856 }
857 }
858 },
859 b'f' => { match mac.next() {
861 Some(b) if !matches!(byte_cmd(b), Space) => {
862 match b {
863 b'z' => { push!(Value::N(st.mstk.len().into()));
865 },
866 b'r' => { st.mstk.reverse();
868 },
869 b'R' => { if let Some(va) = st.mstk.pop() {
871 if let Value::N(r) = &*va {
872 match usize::try_from(r) {
873 Ok(0) => {}, Ok(u) => {
875 if let Some(from) = st.mstk.len().checked_sub(u) {
876 st.mstk[from..].reverse();
877 }
878 else {
879 st.mstk.push(va);
880 valerr!('f', "Can't reverse {} values, stack depth is {}", u, st.mstk.len() - 1);
881 }
882 }
883 Err(_) => {
884 let vs = va.to_string();
885 st.mstk.push(va);
886 valerr!('f', "Can't possibly reverse {} values", vs);
887 }
888 }
889 }
890 else {
891 let ta = TypeLabel::from(&*va);
892 st.mstk.push(va);
893 synerr!('f', "Expected a number, {} given", ta);
894 }
895 }
896 else {
897 synerr!('f', "Expected 1 argument, 0 given");
898 }
899 },
900 b'f' => { let ri = if let Some(r) = rptr.take() {r}
902 else {
903 if matches!(mac.next().map(|b| {mac.back(); byte_cmd(b)}), None | Some(Space)) {
904 synerr!('f', "No register index");
905 alt = false;
906 continue 'cmd;
907 }
908 Rational::from(
909 match mac.try_next_char() {
910 Ok(c) => {c as u32},
911 Err(e) => {
912 *count = Natural::ZERO;
913 synerr!('\0', "Aborting invalid macro: {}", e);
914 break 'cmd;
915 }
916 }
917 )
918 };
919 let reg = st.regs.get_mut(&ri);
920 std::mem::swap(&mut st.mstk, &mut reg.v);
921 },
922 b'p' => { for v in &st.mstk {
924 let vs = v.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
925 if let Some(s) = &mut pbuf {
926 s.push_str(&vs);
927 s.push('\n');
928 }
929 else {
930 let out = &mut io.lock().unwrap().1;
931 writeln!(out, "{}", vs)?;
932 out.flush()?;
933 }
934 }
935 },
936 _ => {
937 synerr!('f', "Invalid stack command 'f{}'", b as char);
938 }
939 }
940 },
941 Some(_) | None => {
942 synerr!('f', "Incomplete stack command 'f'");
943 }
944 }
945 },
946 b'N' => {
947 match (st.mstk.pop(), alt) {
948 (Some(va), false) => { match &*va {
950 Value::N(r) => {
951 match Natural::try_from(r) {
952 Ok(n) => {
953 push!(Value::N(Rational::from(
954 malachite::natural::random::get_random_natural_less_than(rng.get_or_insert_with(rng_os), &n)
955 )));
956 },
957 _ => {
958 st.mstk.push(va);
959 valerr!('N', "Limit must be a natural number");
960 }
961 }
962 },
963 _ => {
964 let ta = TypeLabel::from(&*va);
965 st.mstk.push(va);
966 synerr!('N', "Expected a number, {} given", ta);
967 }
968 }
969 }
970 (Some(va), true) => { match &*va {
972 Value::N(r) => {
973 match Integer::try_from(r) {
974 Ok(Integer::NEGATIVE_ONE) => { rng = None;
976 },
977 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();
980 bytes.resize(32, 0);
981 rng = Some(rng_preset( unsafe { <[u8; 32]>::try_from(bytes).unwrap_unchecked() } ));
982 },
983 _ => {
984 st.mstk.push(va);
985 valerr!('N', "Seed must be a natural number or `1");
986 }
987 }
988 },
989 _ => {
990 let ta = TypeLabel::from(&*va);
991 st.mstk.push(va);
992 synerr!('N', "Expected a number, {} given", ta);
993 }
994 }
995 }
996 (None, _) => {
997 synerr!('N', "Expected 1 argument, 0 given");
998 }
999 }
1000 },
1001 b'w' => { if let Some(va) = st.mstk.pop() {
1003 if let Value::N(r) = &*va {
1004 if let Some(dur) = Natural::try_from(r).ok().and_then(|n| {
1005 let (s, ns) = n.div_rem(Natural::const_from(1_000_000_000));
1006 u64::try_from(&s).ok().map(|s| {
1007 let ns = unsafe { u32::try_from(&ns).unwrap_unchecked() }; std::time::Duration::new(s, ns)
1009 })
1010 }) {
1011 if let Some(rx) = kill {
1012 match rx.recv_timeout(dur) {
1013 Ok(()) => { #[expect(unused_assignments)]
1015 for s in st.regs.end_threads(true) { valerr!('j', s);
1017 }
1018 return Ok(Killed);
1019 },
1020 Err(RecvTimeoutError::Timeout) => { },
1023 Err(RecvTimeoutError::Disconnected) => { unreachable!()
1025 }
1026 }
1027 }
1028 else {
1029 std::thread::sleep(dur); }
1031 }
1032 else {
1033 let vs = va.to_string();
1034 st.mstk.push(va);
1035 valerr!('w', "Can't possibly wait {} ns", vs);
1036 }
1037 }
1038 else {
1039 let ta = TypeLabel::from(&*va);
1040 st.mstk.push(va);
1041 synerr!('w', "Expected a number, {} given", ta);
1042 }
1043 }
1044 else {
1045 synerr!('w', "Expected 1 argument, 0 given");
1046 }
1047 },
1048 b'_' => { let mut word = Vec::new();
1050 while let Some(b) = mac.next() {
1051 if matches!(byte_cmd(b), Space) {
1052 mac.back();
1053 break;
1054 }
1055 else {
1056 word.push(b);
1057 }
1058 }
1059
1060 match &word[..] { b"restrict" => {
1062 #[cfg_attr(feature = "no_os", allow(unused_assignments))] { restrict = true; }
1063 },
1064 b"quiet" => {
1065 ll = LogLevel::Quiet;
1066 },
1067 b"error" => {
1068 ll = LogLevel::Normal;
1069 },
1070 b"debug" => {
1071 ll = LogLevel::Debug;
1072 },
1073 b"err" => {
1074 push!(Value::A(
1075 if let Some((n, c, s)) = elatch.take() {
1076 vec![
1077 Value::N(n.into()),
1078 Value::S(c.into()),
1079 Value::S(s)
1080 ]
1081 }
1082 else { vec![] }
1083 ));
1084 },
1085 b"th" => {
1086 push!(Value::S(th_name.clone()));
1087 },
1088 b"joinall" => {
1089 for s in st.regs.end_threads(false) {
1090 valerr!('j', s);
1091 }
1092 },
1093 b"killall" => {
1094 for s in st.regs.end_threads(true) {
1095 valerr!('j', s);
1096 }
1097 },
1098 b"trim" => {
1099 st.trim();
1100 RE_CACHE.clear();
1101 },
1102 b"clhist" => {
1103 io.lock().unwrap().0.clear_history();
1104 },
1105 b"clpar" => {
1106 st.params = ParamStk::default();
1107 },
1108 b"clall" => {
1109 st.clear_vals();
1110 RE_CACHE.clear();
1111 },
1112 _ => {
1113 #[cfg(feature = "no_os")]
1114 {
1115 synerr!('_', "Invalid word command '{}'", string_or_bytes(&word));
1116 }
1117 #[cfg(not(feature = "no_os"))]
1118 {
1119 match (restrict, os::OS_CMDS.get(&word).copied()) {
1120 (false, Some(oscmd)) => {
1121 match unsafe { oscmd(st) } { Ok(mut v) => {
1123 append!(v);
1124 }
1125 Err(e) => {
1126 if let Some(se) = e.strip_suffix('!') {
1127 synerr!('_', "OS command '{}': {}", string_or_bytes(&word), se);
1128 }
1129 else {
1130 valerr!('_', "OS command '{}': {}", string_or_bytes(&word), e);
1131 }
1132 }
1133 }
1134 }
1135 (true, Some(_)) => {
1136 synerr!('_', "OS command '{}' is disabled (restricted mode)", string_or_bytes(&word));
1137 },
1138 _ => {
1139 synerr!('_', "Invalid word command '{}'", string_or_bytes(&word));
1140 }
1141 }
1142 }
1143 }
1144 }
1145 },
1146 _ => unreachable!()
1147 }
1148 },
1149 ExecR => {
1150 let ri = if let Some(r) = rptr.take() {r}
1151 else {
1152 if matches!(mac.next().map(|b| {mac.back(); byte_cmd(b)}), None | Some(Space)) {
1153 synerr!(b as char, "No register index");
1154 alt = false;
1155 continue 'cmd;
1156 }
1157 Rational::from(
1158 match mac.try_next_char() {
1159 Ok(c) => {c as u32},
1160 Err(e) => {
1161 *count = Natural::ZERO;
1162 synerr!('\0', "Aborting invalid macro: {}", e);
1163 break 'cmd;
1164 }
1165 }
1166 )
1167 };
1168 debug!("Register command {}{}", if alt {"alt-"} else {""}, b as char);
1169 match b {
1170 b'Z' => { push!(Value::N(
1172 st.regs.try_get(&ri).map(|reg| reg.v.len().into()).unwrap_or_default()
1173 ));
1174 },
1175 b's' => {
1176 if let Some(va) = st.mstk.pop() {
1177 let reg = st.regs.get_mut(&ri);
1178 if let Some(rv) = reg.v.last_mut() {
1179 *rv = va;
1180 }
1181 else {
1182 reg.v.push(va);
1183 }
1184 }
1185 else {
1186 synerr!('s', "Stack is empty");
1187 }
1188 },
1189 b'S' => {
1190 if let Some(va) = st.mstk.pop() {
1191 st.regs.get_mut(&ri).v.push(va);
1192 }
1193 else {
1194 synerr!('S', "Stack is empty");
1195 }
1196 },
1197 b'l' => {
1198 if let Some(rv) = st.regs.try_get(&ri).and_then(|reg| reg.v.last()) {
1199 if let Some(p) = dest.last_mut() { unsafe {
1201 p.as_mut().push((**rv).clone()); }
1203 }
1204 else {
1205 st.mstk.push(Arc::clone(rv));
1206 }
1207 }
1208 else {
1209 synerr!('l', "Register {} is empty", reg_index_nice(&ri));
1210 }
1211 },
1212 b'L' => {
1213 if let Some(rv) = st.regs.try_get_mut(&ri).and_then(|reg| reg.v.pop()) {
1214 if let Some(p) = dest.last_mut() { unsafe {
1216 p.as_mut().push((*rv).clone()); }
1218 }
1219 else {
1220 st.mstk.push(Arc::clone(&rv));
1221 }
1222 }
1223 else {
1224 synerr!('L', "Register {} is empty", reg_index_nice(&ri));
1225 }
1226 },
1227 b'X' => {
1228 if let Some(true) = st.regs.try_get(&ri).map(|reg| reg.th.is_some()) {
1229 valerr!('X', "Register {} is already running a thread", reg_index_nice(&ri));
1230 }
1231 else if let Some(va) = st.mstk.pop() {
1232 if let Value::S(sa) = &*va {
1233 let th_start = sa.to_owned().into();
1234 let (ktx, krx) = std::sync::mpsc::channel::<()>();
1235 let (jtx, jrx) = std::sync::mpsc::channel::<()>();
1236 let tb = std::thread::Builder::new().name(format!("{th_name}{}: ", reg_index_nice(&ri)));
1237 let mut th_st = if alt { st.clone() } else { State::default() };
1238 let th_io = Arc::clone(&io);
1239
1240 match tb.spawn(move || {
1241 let th_res = interpreter_no_os(&mut th_st, th_start, Arc::clone(&th_io), ll, Some(&krx));
1242
1243 let _ = jrx.recv(); th_st.regs.end_threads( matches!(th_res, Ok(Killed) | Err(_)) ||
1247 match krx.try_recv() { Ok(()) => { true },
1249 Err(TryRecvError::Empty) => { false },
1250 Err(TryRecvError::Disconnected) => { unreachable!() } }
1252 );
1253
1254 (th_st.mstk, th_res)
1255 }) {
1256 Ok(jh) => {
1257 st.regs.get_mut(&ri).th = Some((jh, ktx, jtx));
1258 },
1259 Err(e) => {
1260 valerr!('X', "Can't spawn child thread: {}", e);
1261 }
1262 }
1263 }
1264 else {
1265 let ta = TypeLabel::from(&*va);
1266 st.mstk.push(va);
1267 synerr!('X', "Expected a string, {} given", ta);
1268 }
1269 }
1270 else {
1271 synerr!('X', "Expected 1 argument, 0 given");
1272 }
1273 },
1274 b'j' => {
1275 if let Some(reg) = st.regs.try_get_mut(&ri) && let Some((jh, ktx, jtx)) = reg.th.take() {
1276 if alt {
1277 ktx.send(()).unwrap_or_else(|_| panic!("Thread {} panicked, terminating!", reg_index_nice(&ri)));
1278 }
1279 jtx.send(()).unwrap_or_else(|_| panic!("Thread {} panicked, terminating!", reg_index_nice(&ri)));
1280 match jh.join() {
1281 Ok(mut tr) => {
1282 match tr.1 {
1283 Err(e) => {
1284 valerr!('j', "IO error in thread {}: {}", reg_index_nice(&ri), e);
1285 },
1286 Ok(SoftQuit(c)) if c != 0 => {
1287 valerr!('j', "Thread {} quit with code {}", reg_index_nice(&ri), c);
1288 },
1289 Ok(HardQuit(c)) if c != 0 => {
1290 valerr!('j', "Thread {} hard-quit with code {}", reg_index_nice(&ri), c);
1291 },
1292 Ok(Killed) => {
1293 valerr!('j', "Thread {} was killed", reg_index_nice(&ri));
1294 },
1295 _ => {}
1296 }
1297
1298 reg.v.append(&mut tr.0);
1299 },
1300 Err(e) => {
1301 std::panic::resume_unwind(e);
1302 }
1303 }
1304 }
1305 else {
1306 valerr!('j', "Register {} is not running a thread", reg_index_nice(&ri));
1307 }
1308 },
1309 b'J' => {
1310 if let Some(Some((jh, _, _))) = st.regs.try_get(&ri).map(|reg| ®.th) {
1311 let mut bz = BitVec::new();
1312 bz.push(jh.is_finished());
1313 push!(Value::B(bz));
1314 }
1315 else {
1316 valerr!('J', "Register {} is not running a thread", reg_index_nice(&ri));
1317 }
1318 },
1319 _ => unreachable!()
1320 }
1321 },
1322 Lit => {
1323 match b {
1324 b'T' | b'F' => { debug!("Boolean literal");
1326 let mut bits = BitVec::new();
1327 bits.push(b == b'T');
1328 while let Some(b) = mac.next() {
1329 match b {
1330 b'T' => {bits.push(true);},
1331 b'F' => {bits.push(false);},
1332 _ => {
1333 mac.back();
1334 break;
1335 }
1336 }
1337 }
1338 push!(Value::B(bits));
1339 },
1340 b'\'' | b'0'..=b'9' | b'.' | b'@' => { debug!("Number literal");
1342 let mut ipart = Vec::new();
1343 let mut fpart = Vec::new();
1344 let mut rpart = Vec::new();
1345 let mut get_epart = true;
1346 let mut exp = None;
1347 let mut discard = false;
1348 let mut ibase = st.params.get_i().clone();
1349
1350 match (b == b'\'', ibase > Natural::const_from(36)) {
1351 (false, high_base) => { mac.back();
1353 ibase = if high_base {Natural::const_from(10)} else {ibase}; while let Some(ib) = mac.next() { let id = ib.wrapping_sub(0x30);
1356 match id {
1357 0..=9 if id < ibase => {ipart.push(Natural::from(id));},
1358 0..=9 => {
1359 synerr!('\'', "Digit {} is too high for base {}", id, ibase);
1360 discard = true;
1361 },
1362 _ => {
1363 mac.back();
1364 break;
1365 }
1366 }
1367 }
1368 match mac.next() {
1369 Some(b'.') => { let mut recur = false; while let Some(fb) = mac.next() {
1372 let fd = fb.wrapping_sub(0x30);
1373 match fd {
1374 0x30 if !recur => {recur = true;}, 0..=9 if !recur && fd < ibase => {fpart.push(Natural::from(fd));},
1376 0..=9 if recur && fd < ibase => {rpart.push(Natural::from(fd));},
1377 0..=9 => {
1378 synerr!('\'', "Digit {} is too high for base {}", fd, ibase);
1379 discard = true;
1380 },
1381 _ => {
1382 mac.back();
1383 break;
1384 }
1385 }
1386 }
1387 },
1388 Some(_) => {mac.back();},
1389 None => {}
1390 }
1391 }
1392 (true, false) => { while let Some(ib) = mac.next() { if let Some(id) = mixed_ascii_to_digit(ib) {
1395 if id < ibase {ipart.push(Natural::from(id));}
1396 else {
1397 synerr!('\'', "Digit {} is too high for base {}", id, ibase);
1398 discard = true;
1399 }
1400 }
1401 else {
1402 mac.back();
1403 break;
1404 }
1405 }
1406 match mac.next() {
1407 Some(b'.') => { let mut recur = false; while let Some(fb) = mac.next() {
1410 if let Some(fd) = mixed_ascii_to_digit(fb) {
1411 if fd < ibase {
1412 if !recur {fpart.push(Natural::from(fd));}
1413 else {rpart.push(Natural::from(fd));}
1414 }
1415 else {
1416 synerr!('\'', "Digit {} is too high for base {}", fd, ibase);
1417 discard = true;
1418 }
1419 }
1420 else if !recur && fb == b'`' {recur = true;}
1421 else {
1422 mac.back();
1423 break;
1424 }
1425 }
1426 },
1427 Some(_) => {mac.back();},
1428 None => {}
1429 }
1430 },
1431 (true, true) => { get_epart = false;
1433 let ns= mac.by_ref().take_while(|b| *b != b'\'').collect::<Vec<u8>>();
1434 if ns.is_empty() {
1435 synerr!('\'', "Empty any-base number");
1436 alt = false;
1437 continue 'cmd;
1438 }
1439 for nc in ns.iter() {
1440 match nc {
1441 b' ' | b'.' | b'0'..=b'9' | b'@' | b'`' => {} wrong => {
1443 synerr!('\'', "Invalid character in any-base number: {}", string_or_bytes(&[*wrong]));
1444 alt = false;
1445 continue 'cmd;
1446 }
1447 }
1448 }
1449 let mut ms = Vec::new();
1450 match ns.split(|b| *b == b'@').collect::<Vec<&[u8]>>()[..] {
1451 [mpart] => { ms = mpart.to_vec();
1453 },
1454 [mpart, epart] => { ms = mpart.to_vec();
1456 let mut es = epart.to_vec();
1457 if let Some(first) = es.first_mut() && *first == b'`' { *first = b'-'; }
1458 match String::from_utf8(es) {
1459 Ok(es) => {
1460 match es.parse::<i64>() {
1461 Ok(i) => { exp = Some(i); },
1462 Err(e) => {
1463 use std::num::IntErrorKind::*;
1464 match e.kind() {
1465 Empty => { exp = Some(0); },
1466 InvalidDigit => {
1467 valerr!('\'', "Invalid exponent: {}", es);
1468 alt = false;
1469 continue 'cmd;
1470 },
1471 PosOverflow | NegOverflow => {
1472 valerr!('\'', "Exponent {} is unrepresentable", es);
1473 alt = false;
1474 continue 'cmd;
1475 },
1476 _ => { unreachable!() }
1477 }
1478 }
1479 }
1480 },
1481 _ => { unreachable!() }
1482 }
1483 },
1484 ref v => {
1485 synerr!('\'', "{} exponent signs (@) in any-base number", v.len() - 1);
1486 drop(ms);
1487 alt = false;
1488 continue 'cmd;
1489 }
1490 }
1491 let mut is = Vec::new();
1492 let mut frs = Vec::new();
1493 match ms.split(|b| *b == b'.').collect::<Vec<&[u8]>>()[..] {
1494 [ipart] => {
1495 is = ipart.to_vec();
1496 },
1497 [ipart, fpart] => {
1498 is = ipart.to_vec();
1499 frs = fpart.to_vec();
1500 },
1501 ref v => {
1502 synerr!('\'', "{} fractional points (.) in any-base number", v.len() - 1);
1503 drop(is);
1504 alt = false;
1505 continue 'cmd;
1506 }
1507 }
1508 if is.contains(&b'`') {
1509 synerr!('\'', "Unexpected negative sign (`) in any-base number");
1510 alt = false;
1511 continue 'cmd;
1512 }
1513 let mut fs = Vec::new();
1514 let mut rs = Vec::new();
1515 match frs.split(|b| *b == b'`').collect::<Vec<&[u8]>>()[..] {
1516 [fpart] => {
1517 fs = fpart.to_vec();
1518 },
1519 [fpart, rpart] => {
1520 fs = fpart.to_vec();
1521 rs = rpart.to_vec();
1522 },
1523 ref v => {
1524 synerr!('\'', "{} recurring marks (`) in any-base number", v.len() - 1);
1525 drop(fs);
1526 alt = false;
1527 continue 'cmd;
1528 }
1529 }
1530 if !is.is_empty() { for id in is.split(|b| *b == b' ') {
1531 let id = str::from_utf8(id).unwrap();
1532 ipart.push(Natural::from_str(id).unwrap());
1533 }}
1534 if !fs.is_empty() { for fd in fs.split(|b| *b == b' ') {
1535 let fd = str::from_utf8(fd).unwrap();
1536 fpart.push(Natural::from_str(fd).unwrap());
1537 }}
1538 if !rs.is_empty() { for rd in rs.split(|b| *b == b' ') {
1539 let rd = str::from_utf8(rd).unwrap();
1540 rpart.push(Natural::from_str(rd).unwrap());
1541 }}
1542 for d in ipart.iter().chain(fpart.iter()).chain(rpart.iter()) {
1543 if *d >= ibase {
1544 synerr!('\'', "Digit {} is too high for base {}", d, ibase);
1545 alt = false;
1546 continue 'cmd;
1547 }
1548 }
1549 }
1550 }
1551
1552 let m_empty = ipart.is_empty() && fpart.is_empty() && rpart.is_empty(); let mut r;
1554 if m_empty {
1555 r = Rational::ZERO;
1556 }
1557 else {
1558 ipart.reverse(); r = Rational::from_digits(&ibase, ipart, RationalSequence::from_vecs(fpart, rpart));
1560 if alt {r.neg_assign();} }
1562
1563 if get_epart {
1564 match mac.next() {
1565 Some(b'@') => { let mut es = String::new();
1567 let mut eneg = false; while let Some(eb) = mac.next() {
1569 match eb {
1570 b'`' if !eneg => { es.push('-'); }
1571 b'0'..=b'9' => { es.push(eb as char); }
1572 _ => {
1573 mac.back();
1574 break;
1575 }
1576 }
1577 eneg = true; }
1579 if es.is_empty() { es.push('0'); }
1580 if m_empty { r = Rational::ONE; } if let Ok(i) = es.parse::<i64>() {
1582 r *= Rational::from(st.params.get_i()).pow(i); }
1584 else {
1585 valerr!('\'', "Exponent {} is unrepresentable", es);
1586 discard = true;
1587 }
1588 }
1589 Some(_) => { mac.back(); }
1590 None => {}
1591 }
1592 }
1593 else if let Some(i) = exp {
1594 if m_empty { r = Rational::ONE; } r *= Rational::from(ibase).pow(i); }
1597
1598 if !discard {
1599 push!(Value::N(r));
1600 }
1601 },
1602 b'[' => { debug!("String literal");
1604 let mut bytes = Vec::new();
1605 let mut discard = false;
1606 let mut nest = 1usize;
1607 while let Some(b) = mac.next() {
1608 match b {
1609 b'[' => {
1610 nest = unsafe { nest.unchecked_add(1) };
1611 bytes.push(b'[');
1612 },
1613 b']' => {
1614 nest = unsafe { nest.unchecked_sub(1) };
1615 if nest == 0 {
1616 break;
1617 }
1618 else {
1619 bytes.push(b']');
1620 }
1621 },
1622 b'\\' => { match mac.next() {
1624 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() {
1638 if let Some(low) = upper_hex_to_nibble(b1) {
1639 bytes.push(high << 4 | low);
1640 }
1641 else {
1642 synerr!('[', "Invalid byte escape: \\{}{}", b0 as char, b1 as char);
1643 discard = true;
1644 }
1645 }
1646 else {
1647 synerr!('[', "Incomplete byte escape: \\{}", b0 as char);
1648 discard = true;
1649 }
1650 }
1651 else { mac.back();
1653 match mac.try_next_char() {
1654 Ok(c) => {
1655 synerr!('[', "Invalid character escape: \\{} (U+{:04X})", c, c as u32);
1656 discard = true;
1657 },
1658 Err(e) => {
1659 *count = Natural::ZERO;
1660 synerr!('\0', "Aborting invalid macro: {}", e);
1661 break 'cmd;
1662 }
1663 }
1664 }
1665 },
1666 None => {
1667 synerr!('[', "Incomplete character escape: \\");
1668 discard = true;
1669 }
1670 }
1671 },
1672 _ => {
1673 bytes.push(b);
1674 }
1675 }
1676 }
1677 if !discard {
1678 match String::try_from(Utf8Iter::from(bytes)) {
1679 Ok(s) => {
1680 push!(Value::S(s));
1681 },
1682 Err(e) => {
1683 synerr!('[', "Invalid string: {}", e);
1684 }
1685 }
1686 }
1687 },
1688 _ => unreachable!()
1689 }
1690 },
1691 Space if b == b'#' => { debug!("Line comment");
1693 mac.find(|b| *b == b'\n');
1694 },
1695 Space => {
1696 },
1698 Wrong => {
1699 mac.back();
1700 match mac.try_next_char() {
1701 Ok(c) => {
1702 synerr!(c, "Invalid command: {} (U+{:04X})", c, c as u32);
1703 },
1704 Err(e) => {
1705 *count = Natural::ZERO;
1706 synerr!('\0', "Aborting invalid macro: {}", e);
1707 break 'cmd;
1708 }
1709 }
1710 }
1711 }
1712
1713 alt = false; } if !dest.is_empty() { st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
1718 dest.clear(); }
1720
1721 if *count == Natural::ZERO { call.pop();
1723 }
1724 else { mac.rewind();
1726 }
1727 } Ok(Finished)
1730}