adc_lang/
lib.rs

1//! ADC interpreter API. Many safe items are public for manual access.
2
3pub 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
34/// Added at the start of saved state files
35pub 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		//these do not take &mut self, shrug
43		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
50/// Generic input stream adapter trait, used for adding a proper line editor.
51///
52/// Comes with a generic implementation for all [`BufRead`] types.
53pub trait ReadLine {
54	/// This is called once by every execution of the `?` command within ADC.
55	///
56	/// [`ErrorKind::Interrupted`] causes `?` to error, [`ErrorKind::UnexpectedEof`] makes an empty string, other [`ErrorKind`]s are returned early from the interpreter.
57	fn read_line(&mut self) -> std::io::Result<String>;
58
59	/// If [`Self`] has a history, clear it.
60	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		// no history, do nothing
71	}
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
100/// Bundle of standard IO streams, generic interface to support custom IO wrappers
101pub struct IOStreams (
102	/// Input
103	pub Box<dyn ReadLine + Send>,
104	/// Output
105	pub Box<dyn Write + Send>,
106	/// Error
107	pub Box<dyn Write + Send>
108);
109impl IOStreams {
110	/// Use dummy IO streams, these do nothing
111	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	/// Use IO streams of the process (stdin, stdout, stderr), with extra [line editor](linefeed) on stdin
120	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/// How much information to output on stderr
130#[derive(Debug, PartialEq, Eq, Clone, Copy)]
131pub enum LogLevel {
132	/// Only output error messages
133	Normal,
134	/// Report every command (without values) 
135	Debug,
136	/// No error messages, stderr disabled
137	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	///monadic pure function
157	Fn1(fns::Mon),
158
159	///dyadic pure function
160	Fn2(fns::Dya),
161	
162	///triadic pure function
163	Fn3(fns::Tri),
164
165	///impure command
166	Cmd(cmds::Cmd),
167
168	///really impure (macros, IO, OS...)
169	Exec,
170
171	///impure with register access
172	ExecR,
173
174	///begin value literal
175	Lit,
176
177	///no command
178	Space,
179
180	///invalid command
181	#[default] Wrong,
182}
183
184/// Dense map of bytes to commands. SAFETY: Length must be exactly 256.
185const CMDS: [Command; 256] = {
186	use Command::*;
187	use fns::*;
188	use cmds::*;
189	[
190		//NUL		SOH			STX			ETX			EOT			ENQ			ACK			BEL			BS			HT			LF			VT			FF			CR			SO			SI
191		Space,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Space,		Space,		Space,		Space,		Space,		Wrong,		Wrong,
192
193		//DLE		DC1			DC2			DC3			DC4			NAK			SYN			ETB			CAN			EM			SUB			ESC			FS			GS			RS			US
194		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,
195
196		//SP		!			"			#			$			%			&			'			(			)			*			+			,			-			.			/
197		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		//0			1			2			3			4			5			6			7			8			9			:			;			<			=			>			?
200		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Exec,		Wrong,		Fn2(lt),	Fn2(eq),	Fn2(gt),	Exec,
201
202		//@			A			B			C			D			E			F			G			H			I			J			K			L			M			N			O
203		Lit,		Wrong,		Wrong,		Cmd(cln),	Exec,		Wrong,		Lit,		Fn2(logb),	Wrong,		Cmd(gi),	ExecR,		Cmd(gk),	ExecR,		Cmd(gm),	Wrong,		Cmd(go),
204
205		//P			Q			R			S			T			U			V			W			X			Y			Z			[			\			]			^			_
206		Exec,		Exec,		Exec,		ExecR,		Lit,		Wrong,		Wrong,		Wrong,		ExecR,		Wrong,		ExecR,		Lit,		Wrong,		Wrong,		Fn2(pow),	Exec,
207
208		//`			a			b			c			d			e			f			g			h			i			j			k			l			m			n			o
209		Exec,		Exec,		Wrong,		Cmd(cls),	Exec,		Wrong,		Exec,		Fn1(log),	Wrong,		Cmd(si),	ExecR,		Cmd(sk),	ExecR,		Cmd(sm),	Wrong,		Cmd(so),
210
211		//p			q			r			s			t			u			v			w			x			y			z			{			|			}			~			DEL
212		Exec,		Exec,		Cmd(rev),	ExecR,		Wrong,		Wrong,		Wrong,		Exec,		Exec,		Wrong,		Fn1(disc),	Cmd(cbo),	Fn3(bar),	Cmd(cbc),	Fn2(euc),	Wrong,
213
214		//~~description of what i'm doing:~~ non-ASCII:
215		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 {	//SAFETY: length is 256
224		*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)}),	//SAFETY: underflow is impossible
242		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)}),	//SAFETY: underflow is impossible
250		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| {	//if ri is a natural
258		let bytes: Vec<u8> = n.to_power_of_2_digits_desc(8);	//look at its bytes
259		str::from_utf8(&bytes).ok().map(|s| String::from("[") + s + "]")	//if it parses to a string, ri was likely set from one
260	})
261		.unwrap_or_else(|| {
262			num::nauto(ri, DEFAULT_PARAMS.0, &DEFAULT_PARAMS.2)	//or just return the number in canonical notation
263		})
264}
265
266/// Results of running [`interpreter`], wrappers should handle these differently
267#[derive(Clone, Copy, Debug, PartialEq)]
268#[must_use] pub enum ExecResult {
269	/// Commands ran to completion, request further input
270	Finished,
271
272	/// Exit of current instance requested (q), end context
273	SoftQuit(u8),
274
275	/// Complete exit requested (`q), terminate
276	HardQuit(u8)
277}
278
279/// Interpreter entry point, executes ADC commands to modify state
280///
281/// # Arguments
282/// - `st`: State struct to work on, modified in-place
283/// - `start`: Initial commands to run
284/// - `io`: Bundle of IO stream handles
285///   - `io.0`: Input, read by ? one line at a time
286///   - `io.1`: Output, written to by printing commands
287///   - `io.2`: Error messages, one per line
288/// - `ll`: Level of verbosity for `io.2`
289/// - `kill`: Receiver for a kill signal from a parent thread, checked with `try_recv` in the command parsing loop
290/// - `restrict`: Restricted mode switch, prevents OS access (for untrusted input). If `false`, the interpreter may read/write files and execute OS commands, subject to any OS-level permissions.
291///
292/// # Errors
293/// Any IO errors that arise when accessing the IO streams are returned early, aborting the interpreter. Keep that possibility to a minimum when preparing custom IO streams.
294///
295/// # Panics
296/// Shouldn'tâ„¢
297#[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;	//print-to-string buffer
316
317	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	/*macro_rules! debug {
360    	($s:expr) => {
361			if ll == LogLevel::Debug {
362				let err = &mut io.lock().unwrap().2;
363				writeln!(err, "DEBUG: {th_name}{}", $s)?;
364				err.flush()?;
365			}
366		};
367		($f:literal, $($s:expr),*) => {
368			if ll == LogLevel::Debug {
369				let err = &mut io.lock().unwrap().2;
370				writeln!(err, "DEBUG: {th_name}{}", format!($f, $($s),*))?;
371				err.flush()?;
372			}
373		};
374	}*/
375
376	let mut rptr: Option<Rational> = None;	//allow setting by a macro
377
378	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() {	//while call stack has contents, macro scope:
383		*count -= Natural::ONE;
384		let mut alt = false;
385
386		let mut abuf: Vec<Value> = Vec::new();	//array input buffer
387		let mut dest: Vec<NonNull<Vec<Value>>> = Vec::new();	//stack of destinations for new values, shadows mstk with the following macros
388		/// push one value to main stack or array buffer
389		macro_rules! push {
390    		($v:expr) => {
391				if let Some(p) = dest.last_mut() {
392					unsafe {
393						p.as_mut().push($v);	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
394					}
395				}
396				else {
397					st.mstk.push(Arc::new($v));
398				}
399			};
400		}
401		/// append values to main stack or array buffer
402		macro_rules! append {
403    		($v:expr) => {
404				if let Some(p) = dest.last_mut() {
405					unsafe {
406						p.as_mut().append(&mut $v);	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
407					}
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() {	//main parsing loop, single command scope:
418			if let Some(rx) = kill {	//check kill signal
419				match rx.try_recv() {
420					Ok(()) => {	//killed by parent
421						return Ok(Finished);
422					},
423					Err(TryRecvError::Empty) => {	//not killed
424						//do nothing
425					},
426					Err(TryRecvError::Disconnected) => {	//parent should never disconnect
427						unreachable!()
428					}
429				}
430			}
431			
432			if let Some(e) = &mut elatch {	//advance error latch counter
433				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 prefix
526							alt = true;
527							continue 'cmd;	//force digraph
528						},
529						b':' => {	//register pointer
530							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() {	//manual shadowed push
547									unsafe {
548										p.as_mut().push((**v).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
549									}
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) => {},	//no-op
564										Ok(u) => {
565											if let Some(from) = st.mstk.len().checked_sub(u) {
566												if let Some(p) = dest.last_mut() {	//manual shadowed append
567													for v in &st.mstk[from..] {
568														unsafe {
569															p.as_mut().push((**v).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
570														}
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' => {	//rotate
600							if let Some(va) = st.mstk.pop() {
601								if let Value::N(r) = &*va {
602									match usize::try_from(r) {
603										Ok(0) => {},	//no-op
604										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'?' => {	//read line
632							let res = {io.lock().unwrap().0.read_line()};	//drop lock
633							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' => {	//println top
653							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' => {	//print top
670							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'"' => {	//toggle pbuf
686							if let Some(s) = pbuf.take() {	//close
687								push!(Value::S(s));
688							}
689							else {	//open
690								pbuf = Some(String::new());
691							}
692						},
693						b'(' => {	//array input: open
694							let nn = if let Some(p) = dest.last_mut() { unsafe {	//SAFETY: dest is only mutated here, logic is sound
695								p.as_mut().push(Value::A(Vec::new()));	//create nested A
696								let Value::A(new) = &mut p.as_mut().last_mut().unwrap_unchecked() else { std::hint::unreachable_unchecked() };	//and get reference to it
697								NonNull::from(new)
698							}}
699							else {
700								NonNull::from(&mut abuf)	//abuf itself as first layer
701							};
702							dest.push(nn);
703						},
704						b')' => {	//array input: close
705							if dest.pop().is_some() {
706								if dest.is_empty() {	//completed
707									st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));	//commit to stack
708								}
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 {	//sec was not used, return
720											st.mstk.push(sec);
721										}
722
723										if mac.is_finished() && *count == Natural::ZERO {	//tail call optimization: discard current macro if finished
724											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() {	//flush array buffer if not completed
757												st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
758												dest.clear();	//SAFETY: remove leftover dangling references
759											}
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' => {	//array commands
780							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' => {	//stack commands
797							match mac.next() {
798								Some(b) if !matches!(byte_cmd(b), Space) => {
799									match b {
800										b'z' => {	//stack depth
801											push!(Value::N(st.mstk.len().into()));
802										},
803										b'r' => {	//reverse stack
804											st.mstk.reverse();
805										},
806										b'R' => {	//reverse part of stack
807											if let Some(va) = st.mstk.pop() {
808												if let Value::N(r) = &*va {
809													match usize::try_from(r) {
810														Ok(0) => {},	//no-op
811														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' => {	//swap with reg
838											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' => {	//print stack
860											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) => {	//get random natural
886									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) => {	//seed rng
908									match &*va {
909										Value::N(r) => {
910											match Integer::try_from(r) {
911												Ok(Integer::NEGATIVE_ONE) => {	//return to os seed
912													rng = LazyCell::new(rng_os);
913												},
914												Ok(i) if Natural::convertible_from(&i) => {	//custom seed
915													let n= unsafe { Natural::try_from(i).unwrap_unchecked() };	//SAFETY: just checked
916													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' => {	//wait
939							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() };	//SAFETY: remainder always fits
945											std::time::Duration::new(s, ns)
946										})
947									}) {
948										if let Some(rx) = kill {
949											match rx.recv_timeout(dur) {
950												Ok(()) => {	//killed by parent
951													return Ok(Finished);
952												},
953												Err(RecvTimeoutError::Timeout) => {	//wait completed, not killed
954													//do nothing
955												},
956												Err(RecvTimeoutError::Disconnected) => {	//parent should never disconnect
957													unreachable!()
958												}
959											}
960										}
961										else {
962											std::thread::sleep(dur);	//no kill receiver, just sleep
963										}
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'_' => {	//word commands
982							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[..] {	//word commands:
994								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' => {	//stack depth
1093							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() {	//manual shadowed push
1122									unsafe {
1123										p.as_mut().push((**rv).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
1124									}
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() {	//manual shadowed push
1137									unsafe {
1138										p.as_mut().push((*rv).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
1139									}
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 {	//sec was not used, return
1158											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| &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' => {	//booleans
1251							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'@' => {	//numbers
1266							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) => {	//plain
1276									mac.back();
1277									ibase = if high_base {Natural::const_from(10)} else {ibase};	//if plain but I>36, interpret mantissa with I=10
1278									while let Some(ib) = mac.next() {	//integer part
1279										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'.') => {	//fractional part
1294											let mut recur = false;	//recurring digits started
1295											while let Some(fb) = mac.next() {
1296												let fd = fb.wrapping_sub(0x30);
1297												match fd {
1298													0x30 if !recur => {recur = true;},	//b'`' == 0x60
1299													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) => {	//prefixed
1317									while let Some(ib) = mac.next() {	//integer part
1318										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'.') => {	//fractional part
1332											let mut recur = false;	//recurring digits started
1333											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) => {	//enclosed
1356									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'`' => {}	//fine
1366											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] => {	//only mantissa
1376											ms = mpart.to_vec();
1377										},
1378										[mpart, epart] => {	//mantissa and exponent
1379											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();	//simpler const, also keep track of emptiness
1477							let mut r;
1478							if m_empty {
1479								r = Rational::ZERO;
1480							}
1481							else {
1482								ipart.reverse();	//malachite needs reverse order
1483								r = Rational::from_digits(&ibase, ipart, RationalSequence::from_vecs(fpart, rpart));
1484								if alt {r.neg_assign();}	//negative sign was set using alt
1485							}
1486
1487							if get_epart {
1488								match mac.next() {
1489									Some(b'@') => {    //exponent part
1490										let mut es = String::new();
1491										let mut eneg = false;    //negative sign occurred
1492										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;    //only allow on first char
1502										}
1503										if es.is_empty() { es.push('0'); }
1504										if m_empty { r = Rational::ONE; }    //only exponent part
1505										if let Ok(i) = es.parse::<i64>() {
1506											r *= Rational::from(st.params.get_i()).pow(i);    //apply exponent, get original ibase
1507										}
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; }    //only exponent part
1519       							r *= Rational::from(ibase).pow(i);    //apply exponent
1520							}
1521
1522							if !discard {
1523								push!(Value::N(r));
1524							}
1525						},
1526						b'[' => {	//strings
1527							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'\\' => {	//character escapes
1546										match mac.next() {
1547											Some(b'a') => {bytes.push(0x07);},		//bell
1548											Some(b'b') => {bytes.push(0x08);},		//backspace
1549											Some(b't') => {bytes.push(0x09);},		//horizontal tab
1550											Some(b'n') => {bytes.push(0x0A);},		//line feed
1551											Some(b'v') => {bytes.push(0x0B);},		//vertical tab
1552											Some(b'f') => {bytes.push(0x0C);},		//form feed
1553											Some(b'r') => {bytes.push(0x0D);},		//carriage return
1554											Some(b'e') => {bytes.push(0x1B);},		//escape
1555											Some(b'[') => {bytes.push(b'[');},		//literal opening bracket
1556											Some(b']') => {bytes.push(b']');},		//literal closing bracket
1557											Some(b'\\') => {bytes.push(b'\\');},	//literal backslash
1558											Some(b0) => {							//other escapes
1559												if let Some(high) = upper_hex_to_nibble(b0) {	//byte literal
1560													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 {	//wrong escape
1575													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'#' => {	//line comment
1615					mac.find(|b| *b == b'\n');
1616				},
1617				Space => {
1618					//do nothing
1619				},
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;	//reset after digraph
1636		}	//end of command scope
1637
1638		if !dest.is_empty() {	//flush array buffer if not completed
1639			st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
1640			dest.clear();	//SAFETY: remove leftover dangling references
1641		}
1642
1643		if *count == Natural::ZERO {	//all repetitions finished
1644			call.pop();
1645		}
1646		else {	//more to go
1647			mac.rewind();
1648		}
1649	}	//end of macro scope
1650	
1651	Ok(Finished)
1652}