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::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, PowerOf2Digits, 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
36/// Added at the start of saved state files
37pub 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		//these do not take &mut self, shrug
45		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
52/// Generic input stream adapter trait, used for adding a proper line editor.
53///
54/// Comes with a generic implementation for all [`BufRead`] types.
55pub trait ReadLine {
56	/// This is called once by every execution of the `?` command within ADC.
57	///
58	/// [`ErrorKind::Interrupted`] causes `?` to error, [`ErrorKind::UnexpectedEof`] makes an empty string, other [`ErrorKind`]s are returned early from the interpreter.
59	fn read_line(&mut self) -> std::io::Result<String>;
60
61	/// If [`Self`] has a history, clear it.
62	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		// no history, do nothing
73	}
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
102/// Bundle of standard IO streams, generic interface to support custom IO wrappers
103pub struct IOStreams (
104	/// Input
105	pub Box<dyn ReadLine + Send>,
106	/// Output
107	pub Box<dyn Write + Send>,
108	/// Error
109	pub Box<dyn Write + Send>
110);
111impl IOStreams {
112	/// Use dummy IO streams, these do nothing
113	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	/// Use IO streams of the process (stdin, stdout, stderr), with extra [line editor](linefeed) on stdin
122	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
131/// How much information to output on stderr
132#[derive(Debug, PartialEq, Eq, Clone, Copy)]
133pub enum LogLevel {
134	/// Only output error messages
135	Normal,
136	/// Report every command (without values) 
137	Debug,
138	/// No error messages, stderr disabled
139	Quiet
140}
141
142lazy_static::lazy_static! {
143	pub(crate) static ref RE_CACHE: RegexCache = RegexCache::default();
144}
145
146fn rng_preset(bytes: [u8; 32]) -> RandomPrimitiveInts<u64> {
147	malachite::base::num::random::random_primitive_ints(malachite::base::random::Seed::from_bytes(bytes))
148}
149
150fn rng_os() -> RandomPrimitiveInts<u64> {
151	let mut bytes = [0u8; 32];
152	getrandom::fill(&mut bytes).unwrap();
153	rng_preset(bytes)
154}
155
156#[derive(Default, Clone, Copy)]
157enum Command {
158	///monadic pure function
159	Fn1(fns::Mon),
160
161	///dyadic pure function
162	Fn2(fns::Dya),
163	
164	///triadic pure function
165	Fn3(fns::Tri),
166
167	///impure command
168	Cmd(cmds::Cmd),
169
170	///really impure (macros, IO, OS...)
171	Exec,
172
173	///impure with register access
174	ExecR,
175
176	///begin value literal
177	Lit,
178
179	///no command
180	Space,
181
182	///invalid command
183	#[default] Wrong,
184}
185
186/// Dense map of bytes to commands. SAFETY: Length must be exactly 256.
187const CMDS: [Command; 256] = {
188	use Command::*;
189	use fns::*;
190	use cmds::*;
191	[
192		//NUL		SOH			STX			ETX			EOT			ENQ			ACK			BEL			BS			HT			LF			VT			FF			CR			SO			SI
193		Space,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Space,		Space,		Space,		Space,		Space,		Wrong,		Wrong,
194
195		//DLE		DC1			DC2			DC3			DC4			NAK			SYN			ETB			CAN			EM			SUB			ESC			FS			GS			RS			US
196		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,		Wrong,
197
198		//SP		!			"			#			$			%			&			'			(			)			*			+			,			-			.			/
199		Space,		Fn1(neg),	Exec,		Space,		Wrong,		Fn2(modu),	Wrong,		Lit,		Exec,		Exec,		Fn2(mul),	Fn2(add),	Wrong,		Fn2(sub),	Lit,		Fn2(div),
200
201		//0			1			2			3			4			5			6			7			8			9			:			;			<			=			>			?
202		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Lit,		Exec,		Wrong,		Fn2(lt),	Fn2(eq),	Fn2(gt),	Exec,
203
204		//@			A			B			C			D			E			F			G			H			I			J			K			L			M			N			O
205		Lit,		Wrong,		Wrong,		Cmd(cln),	Exec,		Wrong,		Lit,		Fn2(logb),	Wrong,		Cmd(gi),	ExecR,		Cmd(gk),	ExecR,		Cmd(gm),	Exec,		Cmd(go),
206
207		//P			Q			R			S			T			U			V			W			X			Y			Z			[			\			]			^			_
208		Exec,		Exec,		Exec,		ExecR,		Lit,		Wrong,		Fn2(root),	Wrong,		ExecR,		Wrong,		ExecR,		Lit,		Wrong,		Wrong,		Fn2(pow),	Exec,
209
210		//`			a			b			c			d			e			f			g			h			i			j			k			l			m			n			o
211		Exec,		Exec,		Wrong,		Cmd(cls),	Exec,		Wrong,		Exec,		Fn1(log),	Wrong,		Cmd(si),	ExecR,		Cmd(sk),	ExecR,		Cmd(sm),	Fn1(fac),	Cmd(so),
212
213		//p			q			r			s			t			u			v			w			x			y			z			{			|			}			~			DEL
214		Exec,		Exec,		Cmd(rev),	ExecR,		Wrong,		Wrong,		Fn1(sqrt),	Exec,		Exec,		Wrong,		Fn1(disc),	Cmd(cbo),	Fn3(bar),	Cmd(cbc),	Fn2(euc),	Wrong,
215
216		//~~description of what i'm doing:~~ non-ASCII:
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		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,
220		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
221	]
222};
223
224fn byte_cmd(b: u8) -> Command {
225	unsafe {	//SAFETY: length is 256
226		*CMDS.get_unchecked(b as usize)
227	}
228}
229
230fn string_or_bytes(v: &[u8]) -> String {
231	str::from_utf8(v).map(|s| s.to_owned()).unwrap_or_else(|_| {
232		let mut res = String::from("(not UTF-8: [");
233		for b in v {
234			res += &format!("\\{b:02X}");
235		}
236		res += "])";
237		res
238	})
239}
240
241fn upper_hex_to_nibble(b: u8) -> Option<u8> {
242	match b {
243		b'0'..=b'9' => Some(unsafe{b.unchecked_sub(0x30)}),	//SAFETY: underflow is impossible
244		b'A'..=b'F' => Some(unsafe{b.unchecked_sub(0x37)}),
245		_ => None
246	}
247}
248
249fn mixed_ascii_to_digit(b: u8) -> Option<u8> {
250	match b {
251		b'0'..=b'9' => Some(unsafe{b.unchecked_sub(0x30)}),	//SAFETY: underflow is impossible
252		b'A'..=b'Z' => Some(unsafe{b.unchecked_sub(0x37)}),
253		b'a'..=b'z' => Some(unsafe{b.unchecked_sub(0x57)}),
254		_ => None
255	}
256}
257
258fn reg_index_nice(ri: &Rational) -> String {
259	Natural::try_from(ri).ok().and_then(|n| {	//if ri is a natural
260		let bytes: Vec<u8> = n.to_power_of_2_digits_desc(8);	//look at its bytes
261		str::from_utf8(&bytes).ok().map(|s| String::from("[") + s + "]")	//if it parses to a string, ri was likely set from one
262	})
263		.unwrap_or_else(|| {
264			num::nauto(ri, DEFAULT_PARAMS.0, &DEFAULT_PARAMS.2)	//or just return the number in canonical notation
265		})
266}
267
268/// Results of running [`interpreter`], wrappers should handle these differently
269#[derive(Clone, Copy, Debug, PartialEq)]
270#[must_use] pub enum ExecResult {
271	/// Commands ran to completion, request further input
272	Finished,
273
274	/// Exit of current instance requested (q), end context
275	SoftQuit(u8),
276
277	/// Complete exit requested (`q), terminate
278	HardQuit(u8)
279}
280
281/// Safe wrapper around [`interpreter`], see its documentation.
282pub fn interpreter_no_os(
283	st: &mut State,
284	start: Utf8Iter,
285	io: Arc<Mutex<IOStreams>>,
286	ll: LogLevel,
287	kill: Option<&Receiver<()>>,
288) -> std::io::Result<ExecResult>
289{
290	//SAFETY: restrict = true
291	unsafe { interpreter(st, start, io, ll, kill, true) }
292}
293
294/// Interpreter entry point, executes ADC commands to modify state.
295///
296/// # Arguments
297/// - `st`: State struct to work on, modified in-place
298/// - `start`: Initial commands to run
299/// - `io`: Bundle of IO stream handles
300///   - `io.0`: Input, read by ? one line at a time
301///   - `io.1`: Output, written to by printing commands
302///   - `io.2`: Error messages, one per line
303/// - `ll`: Level of verbosity for `io.2`
304/// - `kill`: Receiver for a kill signal from a parent thread, effect is practically immediate
305/// - `restrict`: Restricted mode switch, enable for untrusted input. If `false`, the interpreter may read/write files and execute OS commands, subject to any OS-level permissions.
306///
307/// # Errors
308/// Any IO errors (except those specified [here](ReadLine::read_line)) that arise when accessing the [`IOStreams`] are returned early, aborting the interpreter.
309///
310/// This will result in an incomplete, although internally consistent, [`State`]. Keep that possibility to a minimum when preparing custom [`IOStreams`].
311///
312/// # Safety
313/// If built without the `no_os` feature (default), passing `kill = None` and `restrict = false` enables OS interactions that are fundamentally unsound in multithreaded contexts.
314///
315/// Simultaneously/asynchronously executing multiple instances of this function with said arguments is *Undefined Behavior*. Do not rely on known values of `st` and `start` for safety.
316///
317/// Alternatively, [`interpreter_no_os`] provides a safe wrapper.
318pub unsafe fn interpreter(
319	st: &mut State,
320	start: Utf8Iter,
321	io: Arc<Mutex<IOStreams>>,
322	mut ll: LogLevel,
323	kill: Option<&Receiver<()>>,
324	#[cfg_attr(feature = "no_os", allow(unused_variables))]
325	mut restrict: bool
326) -> std::io::Result<ExecResult>
327{
328	use ExecResult::*;
329
330	let th_name = if kill.is_some() {	//if running in a child thread
331		#[cfg_attr(feature = "no_os", allow(unused_assignments))] { restrict = true; }	//extra safety just in case
332		std::thread::current().name().unwrap().to_owned()
333	}
334	else {
335		String::new()
336	};
337
338	let mut pbuf: Option<String> = None;	//print-to-string buffer
339
340	let mut elatch: Option<(Natural, char, String)> = None;
341
342	macro_rules! synerr {
343		($c:expr, $s:expr) => {
344			if ll != LogLevel::Quiet {
345				let err = &mut io.lock().unwrap().2;
346				writeln!(err, "! {th_name}{}: {}", $c, $s)?;
347				err.flush()?;
348				//drop lock
349			}
350			elatch = Some((Natural::ZERO, $c, $s.into()));
351		};
352    	($c:expr, $f:literal, $($s:expr),*) => {
353			let s = format!($f, $($s),*);
354			if ll != LogLevel::Quiet {
355				let err = &mut io.lock().unwrap().2;
356				writeln!(err, "! {th_name}{}: {}", $c, s)?;
357				err.flush()?;
358				//drop lock
359			}
360			elatch = Some((Natural::ZERO, $c, s));
361		};
362	}
363
364	macro_rules! valerr {
365    	($c:expr, $s:expr) => {
366			if ll != LogLevel::Quiet {
367				let err = &mut io.lock().unwrap().2;
368				writeln!(err, "? {th_name}{}: {}", $c, $s)?;
369				err.flush()?;
370				//drop lock
371			}
372			elatch = Some((Natural::ZERO, $c, $s.into()));
373		};
374		($c:expr, $f:literal, $($s:expr),*) => {
375			let s = format!($f, $($s),*);
376			if ll != LogLevel::Quiet {
377				let err = &mut io.lock().unwrap().2;
378				writeln!(err, "? {th_name}{}: {}", $c, s)?;
379				err.flush()?;
380				//drop lock
381			}
382			elatch = Some((Natural::ZERO, $c, s));
383		};
384	}
385
386	macro_rules! debug {
387    	($s:expr) => {
388			if ll == LogLevel::Debug {
389				let err = &mut io.lock().unwrap().2;
390				writeln!(err, "\tDEBUG: {th_name}{}", $s)?;
391				err.flush()?;
392				//drop lock
393			}
394		};
395		($f:literal, $($s:expr),*) => {
396			if ll == LogLevel::Debug {
397				let err = &mut io.lock().unwrap().2;
398				writeln!(err, "\tDEBUG: {th_name}{}", format!($f, $($s),*))?;
399				err.flush()?;
400				//drop lock
401			}
402		};
403	}
404
405	let mut rptr: Option<Rational> = None;	//allow setting by a macro
406
407	let mut rng: Option<RandomPrimitiveInts<u64>> = None;
408
409	let mut call: Vec<(Utf8Iter, Natural)> = vec![(start, Natural::const_from(1))];
410
411	'mac: while let Some((mac, count)) = call.last_mut() {	//while call stack has contents, macro scope:
412		*count -= Natural::ONE;
413		let mut alt = false;
414
415		let mut abuf: Vec<Value> = Vec::new();	//array input buffer
416		let mut dest: Vec<NonNull<Vec<Value>>> = Vec::new();	//stack of destinations for new values, shadows mstk with the following macros
417		/// push one value to main stack or array buffer
418		macro_rules! push {
419    		($v:expr) => {
420				if let Some(p) = dest.last_mut() {
421					unsafe {
422						p.as_mut().push($v);	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
423					}
424				}
425				else {
426					st.mstk.push(Arc::new($v));
427				}
428			};
429		}
430		/// append values to main stack or array buffer
431		macro_rules! append {
432    		($v:expr) => {
433				if let Some(p) = dest.last_mut() {
434					unsafe {
435						p.as_mut().append(&mut $v);	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
436					}
437				}
438				else {
439					for val in $v {
440						st.mstk.push(Arc::new(val));
441					}
442				}
443			};
444		}
445
446		'cmd: while let Some(b) = mac.next() {	//main parsing loop, single command scope:
447			if let Some(rx) = kill {	//check kill signal
448				match rx.try_recv() {
449					Ok(()) => {	//killed by parent
450						return Ok(Finished);
451					},
452					Err(TryRecvError::Empty) => {	//not killed
453						//do nothing
454					},
455					Err(TryRecvError::Disconnected) => {	//parent should never disconnect
456						unreachable!()
457					}
458				}
459			}
460			
461			if let Some(e) = &mut elatch {	//advance error latch counter
462				e.0 += Natural::ONE;
463			}
464
465			use Command::*;
466			match byte_cmd(b) {
467				Fn1(mon) => {
468					if let Some(va) = st.mstk.pop() {
469						debug!("Monadic {}{} with {}", if alt {"alt-"} else {""}, b as char, TypeLabel::from(&*va));
470						match catch_unwind(|| fns::exec1(mon, &va, alt)) {
471							Ok(Ok(vz)) => {
472								push!(vz);
473							},
474							Ok(Err(e)) => {
475								st.mstk.push(va);
476								valerr!(b as char, e.to_string());
477							},
478							Err(cause) => {
479								st.mstk.push(va);
480								valerr!(b as char, "Caught function panic: {:?}", cause);
481							}
482						}
483					}
484					else {
485						synerr!(b as char, "Expected 1 argument, 0 given");
486					}
487				},
488				Fn2(dya) => {
489					if let Some(vb) = st.mstk.pop() {
490						if let Some(va) = st.mstk.pop() {
491							debug!("Dyadic {}{} with ({}, {})", if alt {"alt-"} else {""}, b as char, TypeLabel::from(&*va), TypeLabel::from(&*vb));
492							match catch_unwind(|| fns::exec2(dya, &va, &vb, alt)) {
493								Ok(Ok(vz)) => {
494									push!(vz);
495								},
496								Ok(Err(e)) => {
497									st.mstk.push(va);
498									st.mstk.push(vb);
499									valerr!(b as char, e.to_string());
500								},
501								Err(cause) => {
502									st.mstk.push(va);
503									st.mstk.push(vb);
504									valerr!(b as char, "Caught function panic: {:?}", cause);
505								}
506							}
507						}
508						else {
509							st.mstk.push(vb);
510							synerr!(b as char, "Expected 2 arguments, 1 given");
511						}
512					}
513					else {
514						synerr!(b as char, "Expected 2 arguments, 0 given");
515					}
516				},
517				Fn3(tri) => {
518					if let Some(vc) = st.mstk.pop() {
519						if let Some(vb) = st.mstk.pop() {
520							if let Some(va) = st.mstk.pop() {
521								debug!("Triadic {}{} with ({}, {}, {})", if alt {"alt-"} else {""}, b as char, TypeLabel::from(&*va), TypeLabel::from(&*vb), TypeLabel::from(&*vc));
522								match catch_unwind(|| fns::exec3(tri, &va, &vb, &vc, alt)) {
523									Ok(Ok(vz)) => {
524										push!(vz);
525									},
526									Ok(Err(e)) => {
527										st.mstk.push(va);
528										st.mstk.push(vb);
529										st.mstk.push(vc);
530										valerr!(b as char, e.to_string());
531									},
532									Err(cause) => {
533										st.mstk.push(va);
534										st.mstk.push(vb);
535										st.mstk.push(vc);
536										valerr!(b as char, "Caught function panic: {:?}", cause);
537									}
538								}
539							}
540							else {
541								st.mstk.push(vb);
542								st.mstk.push(vc);
543								synerr!(b as char, "Expected 3 arguments, 2 given");
544							}
545						}
546						else {
547							st.mstk.push(vc);
548							synerr!(b as char, "Expected 3 arguments, 1 given");
549						}
550					}
551					else {
552						synerr!(b as char, "Expected 3 arguments, 0 given");
553					}
554				},
555				Cmd(cmd) => {
556					debug!("Impure command {}", b as char);
557					match cmd(st) {
558						Ok(mut v) => {
559							append!(v);
560						}
561						Err(e) => {
562							if let Some(se) = e.strip_suffix('!') {
563								synerr!(b as char, se);
564							}
565							else {
566								valerr!(b as char, e);
567							}
568						}
569					}
570				},
571				Exec => {
572					debug!("Special command {}{}", if alt {"alt-"} else {""}, b as char);
573					match b {
574						b'`' => {	//alt prefix
575							alt = true;
576							continue 'cmd;	//force digraph
577						},
578						b':' if !alt => {	//set register pointer
579							if let Some(va) = st.mstk.pop() {
580								if let Value::N(r) = &*va {
581									rptr = Some(r.clone());
582								}
583								else {
584									let ta = TypeLabel::from(&*va);
585									st.mstk.push(va);
586									synerr!(':', "Expected a number, {} given", ta);
587								}
588							}
589							else {
590								synerr!(':', "Expected 1 argument, 0 given");
591							}
592						},
593						b':' if alt => {	//get register pointer
594							push!(
595								if let Some(ri) = rptr.take() {
596									Value::N(ri)
597								}
598								else {
599									Value::A(vec![])
600								}
601							);
602						},
603						b'd' => {
604							if let Some(v) = st.mstk.last() {
605								if let Some(p) = dest.last_mut() {	//manual shadowed push
606									unsafe {
607										p.as_mut().push((**v).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
608									}
609								}
610								else {
611									st.mstk.push(Arc::clone(v));
612								}
613							}
614							else {
615								synerr!('d', "Stack is empty");
616							}
617						},
618						b'D' => {
619							if let Some(va) = st.mstk.pop() {
620								if let Value::N(r) = &*va {
621									match usize::try_from(r) {
622										Ok(0) => {},	//no-op
623										Ok(u) => {
624											if let Some(from) = st.mstk.len().checked_sub(u) {
625												if let Some(p) = dest.last_mut() {	//manual shadowed append
626													for v in &st.mstk[from..] {
627														unsafe {
628															p.as_mut().push((**v).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
629														}
630													}
631												}
632												else {
633													st.mstk.extend_from_within(from..);
634												}
635											}
636											else {
637												st.mstk.push(va);
638												valerr!('D', "Can't duplicate {} values, stack depth is {}", u, st.mstk.len() - 1);
639											}
640										}
641										Err(_) => {
642											let vs = va.to_string();
643											st.mstk.push(va);
644											valerr!('D', "Can't possibly duplicate {} values", vs);
645										}
646									}
647								}
648								else {
649									let ta = TypeLabel::from(&*va);
650									st.mstk.push(va);
651									synerr!('D', "Expected a number, {} given", ta);
652								}
653							}
654							else {
655								synerr!('D', "Expected 1 argument, 0 given");
656							}
657						},
658						b'R' => {	//rotate
659							if let Some(va) = st.mstk.pop() {
660								if let Value::N(r) = &*va {
661									match usize::try_from(r) {
662										Ok(0) => {},	//no-op
663										Ok(u) => {
664											if let Some(from) = st.mstk.len().checked_sub(u) {
665												if alt {st.mstk[from..].rotate_left(1);}
666												else {st.mstk[from..].rotate_right(1);}
667											}
668											else {
669												st.mstk.push(va);
670												valerr!('R', "Can't rotate {} values, stack depth is {}", u, st.mstk.len() - 1);
671											}
672										}
673										Err(_) => {
674											let vs = va.to_string();
675											st.mstk.push(va);
676											valerr!('R', "Can't possibly rotate {} values", vs);
677										}
678									}
679								}
680								else {
681									let ta = TypeLabel::from(&*va);
682									st.mstk.push(va);
683									synerr!('R', "Expected a number, {} given", ta);
684								}
685							}
686							else {
687								synerr!('R', "Expected 1 argument, 0 given");
688							}
689						},
690						b'?' => {	//read line
691							let res = {
692								let inp = &mut io.lock().unwrap().0;
693								inp.read_line()
694								//drop lock
695							};
696							match res {
697								Ok(s) => {
698									push!(Value::S(s));
699								},
700								Err(e) => {
701									match e.kind() {
702										ErrorKind::Interrupted => {
703											valerr!('?', "Interrupted");
704										},
705										ErrorKind::UnexpectedEof => {
706											push!(Value::S(String::new()));
707										},
708										_ => {
709											return Err(e);
710										}
711									}
712								}
713							}
714						},
715						b'p' => {	//println top
716							if let Some(va) = st.mstk.pop() {
717								let vs = va.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
718								if let Some(s) = &mut pbuf {
719									s.push_str(&vs);
720									s.push('\n');
721								}
722								else {
723									let out = &mut io.lock().unwrap().1;
724									writeln!(out, "{}", vs)?;
725									out.flush()?;
726									//drop lock
727								}
728							}
729							else {
730								synerr!('p', "Expected 1 argument, 0 given");
731							}
732						},
733						b'P' => {	//print top
734							if let Some(va) = st.mstk.pop() {
735								let vs = va.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
736								if let Some(s) = &mut pbuf {
737									s.push_str(&vs);
738								}
739								else {
740									let out = &mut io.lock().unwrap().1;
741									write!(out, "{}", vs)?;
742									out.flush()?;
743									//drop lock
744								}
745							}
746							else {
747								synerr!('P', "Expected 1 argument, 0 given");
748							}
749						},
750						b'"' => {	//toggle pbuf
751							if let Some(s) = pbuf.take() {	//close
752								push!(Value::S(s));
753							}
754							else {	//open
755								pbuf = Some(String::new());
756							}
757						},
758						b'(' => {	//array input: open
759							let nn = if let Some(p) = dest.last_mut() { unsafe {	//SAFETY: dest is only mutated here, logic is sound
760								p.as_mut().push(Value::A(Vec::new()));	//create nested A
761								let Value::A(new) = &mut p.as_mut().last_mut().unwrap_unchecked() else { std::hint::unreachable_unchecked() };	//and get reference to it
762								NonNull::from(new)
763							}}
764							else {
765								NonNull::from(&mut abuf)	//abuf itself as first layer
766							};
767							dest.push(nn);
768						},
769						b')' => {	//array input: close
770							if dest.pop().is_some() {
771								if dest.is_empty() {	//completed
772									st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));	//commit to stack
773								}
774							}
775							else {
776								synerr!(')', "Mismatched closing ')'");
777							}
778						},
779						b'x' => {
780							if let Some(top) = st.mstk.pop() {
781								let sec = st.mstk.pop();
782								match Utf8Iter::from_vals(&top, sec.as_deref()) {
783									Ok((mut stk, ret)) => {
784										if let Some(sec) = sec && ret {	//sec was not used, return
785											st.mstk.push(sec);
786										}
787
788										if mac.is_finished() && *count == Natural::ZERO {	//tail call optimization: discard current macro if finished
789											call.pop();
790										}
791
792										call.append(&mut stk);
793										continue 'mac;
794									},
795									Err(e) => {
796										if let Some(sec) = sec {st.mstk.push(sec);}
797										st.mstk.push(top);
798										synerr!('x', "{}", e);
799									}
800								}
801							}
802							else {
803								synerr!('x', "Expected 1 or 2 arguments, 0 given");
804							}
805						},
806						b'q' => {
807							let u = u8::wrapping_from(&Integer::rounding_from(rptr.unwrap_or_default(), RoundingMode::Down).0);
808							return if alt {
809								Ok(HardQuit(u))
810							}
811							else {
812								Ok(SoftQuit(u))
813							};
814						},
815						b'Q' => {
816							if let Some(va) = st.mstk.pop() {
817								match &*va {
818									Value::N(r) => {
819										if let Ok(u) = usize::try_from(r) {
820											call.truncate(call.len().saturating_sub(u));
821											if !dest.is_empty() {	//flush array buffer if not completed
822												st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
823												dest.clear();	//SAFETY: remove leftover dangling references
824											}
825											continue 'mac;
826										}
827										else {
828											let vs = va.to_string();
829											st.mstk.push(va);
830											valerr!('Q', "Cannot possibly break {} macros", vs);
831										}
832									},
833									_ => {
834										let ta = TypeLabel::from(&*va);
835										st.mstk.push(va);
836										synerr!('Q', "Expected a number, {} given", ta);
837									}
838								}
839							}
840							else {
841								synerr!('Q', "Expected 1 argument, 0 given");
842							}
843						},
844						b'a' => {	//array commands
845							match mac.next() {
846								Some(b) if !matches!(byte_cmd(b), Space) => {
847									match b {
848										b'a' => {
849											todo!()
850										},
851										_ => {
852											synerr!('a', "Invalid array command 'a{}'", b as char);
853										}
854									}
855								},
856								Some(_) | None => {
857									synerr!('a', "Incomplete array command 'a'");
858								}
859							}
860						},
861						b'f' => {	//stack commands
862							match mac.next() {
863								Some(b) if !matches!(byte_cmd(b), Space) => {
864									match b {
865										b'z' => {	//stack depth
866											push!(Value::N(st.mstk.len().into()));
867										},
868										b'r' => {	//reverse stack
869											st.mstk.reverse();
870										},
871										b'R' => {	//reverse part of stack
872											if let Some(va) = st.mstk.pop() {
873												if let Value::N(r) = &*va {
874													match usize::try_from(r) {
875														Ok(0) => {},	//no-op
876														Ok(u) => {
877															if let Some(from) = st.mstk.len().checked_sub(u) {
878																st.mstk[from..].reverse();
879															}
880															else {
881																st.mstk.push(va);
882																valerr!('f', "Can't reverse {} values, stack depth is {}", u, st.mstk.len() - 1);
883															}
884														}
885														Err(_) => {
886															let vs = va.to_string();
887															st.mstk.push(va);
888															valerr!('f', "Can't possibly reverse {} values", vs);
889														}
890													}
891												}
892												else {
893													let ta = TypeLabel::from(&*va);
894													st.mstk.push(va);
895													synerr!('f', "Expected a number, {} given", ta);
896												}
897											}
898											else {
899												synerr!('f', "Expected 1 argument, 0 given");
900											}
901										},
902										b'f' => {	//swap with reg
903											let ri = if let Some(r) = rptr.take() {r}
904											else {
905												if matches!(mac.next().map(|b| {mac.back(); byte_cmd(b)}), None | Some(Space)) {
906													synerr!('f', "No register index");
907													alt = false;
908													continue 'cmd;
909												}
910												Rational::from(
911													match mac.try_next_char() {
912														Ok(c) => {c as u32},
913														Err(e) => {
914															*count = Natural::ZERO;
915															synerr!('\0', "Aborting invalid macro: {}", e);
916															break 'cmd;
917														}
918													}
919												)
920											};
921											let reg = st.regs.get_mut(&ri);
922											std::mem::swap(&mut st.mstk, &mut reg.v);
923										},
924										b'p' => {	//print stack
925											for v in &st.mstk {
926												let vs = v.display(st.params.get_k(), st.params.get_o(), st.params.get_m(), alt);
927												if let Some(s) = &mut pbuf {
928													s.push_str(&vs);
929													s.push('\n');
930												}
931												else {
932													let out = &mut io.lock().unwrap().1;
933													writeln!(out, "{}", vs)?;
934													out.flush()?;
935												}
936											}
937										},
938										_ => {
939											synerr!('f', "Invalid stack command 'f{}'", b as char);
940										}
941									}
942								},
943								Some(_) | None => {
944									synerr!('f', "Incomplete stack command 'f'");
945								}
946							}
947						},
948						b'N' => {
949							match (st.mstk.pop(), alt) {
950								(Some(va), false) => {	//get random natural
951									match &*va {
952										Value::N(r) => {
953											match Natural::try_from(r) {
954												Ok(n) => {
955													push!(Value::N(Rational::from(
956														malachite::natural::random::get_random_natural_less_than(rng.get_or_insert_with(rng_os), &n)
957													)));
958												},
959												_ => {
960													st.mstk.push(va);
961													valerr!('N', "Limit must be a natural number");
962												}
963											}
964										},
965										_ => {
966											let ta = TypeLabel::from(&*va);
967											st.mstk.push(va);
968											synerr!('N', "Expected a number, {} given", ta);
969										}
970									}
971								}
972								(Some(va), true) => {	//seed rng
973									match &*va {
974										Value::N(r) => {
975											match Integer::try_from(r) {
976												Ok(Integer::NEGATIVE_ONE) => {	//return to os seed (lazy init)
977													rng = None;
978												},
979												Ok(i) if Natural::convertible_from(&i) => {	//custom seed
980													let n= unsafe { Natural::try_from(i).unwrap_unchecked() };	//SAFETY: just checked
981													let mut bytes: Vec<u8> = PowerOf2DigitIterable::<u8>::power_of_2_digits(&n, 8).take(32).collect();
982													bytes.resize(32, 0);
983													rng = Some(rng_preset( unsafe { <[u8; 32]>::try_from(bytes).unwrap_unchecked() } ));
984												},
985												_ => {
986													st.mstk.push(va);
987													valerr!('N', "Seed must be a natural number or `1");
988												}
989											}
990										},
991										_ => {
992											let ta = TypeLabel::from(&*va);
993											st.mstk.push(va);
994											synerr!('N', "Expected a number, {} given", ta);
995										}
996									}
997								}
998								(None, _) => {
999									synerr!('N', "Expected 1 argument, 0 given");
1000								}
1001							}
1002						},
1003						b'w' => {	//wait
1004							if let Some(va) = st.mstk.pop() {
1005								if let Value::N(r) = &*va {
1006									if let Some(dur) = Natural::try_from(r).ok().and_then(|n| {
1007										let (s, ns) = n.div_rem(Natural::const_from(1_000_000_000));
1008										u64::try_from(&s).ok().map(|s| {
1009											let ns = unsafe { u32::try_from(&ns).unwrap_unchecked() };	//SAFETY: remainder always fits
1010											std::time::Duration::new(s, ns)
1011										})
1012									}) {
1013										if let Some(rx) = kill {
1014											match rx.recv_timeout(dur) {
1015												Ok(()) => {	//killed by parent
1016													return Ok(Finished);
1017												},
1018												Err(RecvTimeoutError::Timeout) => {	//wait completed, not killed
1019													//do nothing
1020												},
1021												Err(RecvTimeoutError::Disconnected) => {	//parent should never disconnect
1022													unreachable!()
1023												}
1024											}
1025										}
1026										else {
1027											std::thread::sleep(dur);	//no kill receiver, just sleep
1028										}
1029									}
1030									else {
1031										let vs = va.to_string();
1032										st.mstk.push(va);
1033										valerr!('w', "Can't possibly wait {} ns", vs);
1034									}
1035								}
1036								else {
1037									let ta = TypeLabel::from(&*va);
1038									st.mstk.push(va);
1039									synerr!('w', "Expected a number, {} given", ta);
1040								}
1041							}
1042							else {
1043								synerr!('w', "Expected 1 argument, 0 given");
1044							}
1045						},
1046						b'_' => {	//word commands
1047							let mut word = Vec::new();
1048							while let Some(b) = mac.next() {
1049								if matches!(byte_cmd(b), Space) {
1050									mac.back();
1051									break;
1052								}
1053								else {
1054									word.push(b);
1055								}
1056							}
1057
1058							match &word[..] {	//word commands:
1059								b"restrict" => {
1060									#[cfg_attr(feature = "no_os", allow(unused_assignments))] { restrict = true; }
1061								},
1062								b"quiet" => {
1063									ll = LogLevel::Quiet;
1064								},
1065								b"error" => {
1066									ll = LogLevel::Normal;
1067								},
1068								b"debug" => {
1069									ll = LogLevel::Debug;
1070								},
1071								b"err" => {
1072									push!(Value::A(
1073										if let Some((n, c, s)) = elatch.take() {
1074											vec![
1075												Value::N(n.into()),
1076												Value::S(c.into()),
1077												Value::S(s)
1078											]
1079										}
1080										else { vec![] }
1081									));
1082								},
1083								b"th" => {
1084									push!(Value::S(th_name.clone()));
1085								},
1086								b"trim" => {
1087									st.trim();
1088									RE_CACHE.clear();
1089								},
1090								b"clhist" => {
1091									io.lock().unwrap().0.clear_history();
1092								},
1093								b"clpar" => {
1094									st.params = ParamStk::default();
1095								},
1096								b"clall" => {
1097									st.clear_vals();
1098									RE_CACHE.clear();
1099								},
1100								_ => {
1101									#[cfg(feature = "no_os")]
1102									{
1103										synerr!('_', "Invalid word command '{}'", string_or_bytes(&word));
1104									}
1105									#[cfg(not(feature = "no_os"))]
1106									{
1107										match (restrict, os::OS_CMDS.get(&word).copied()) {
1108											(false, Some(oscmd)) => {
1109												match unsafe { oscmd(st) } {	//SAFETY: only reachable in the main thread, according to interpreter contract
1110													Ok(mut v) => {
1111														append!(v);
1112													}
1113													Err(e) => {
1114														if let Some(se) = e.strip_suffix('!') {
1115															synerr!('_', "OS command '{}': {}", string_or_bytes(&word), se);
1116														}
1117														else {
1118															valerr!('_', "OS command '{}': {}", string_or_bytes(&word), e);
1119														}
1120													}
1121												}
1122											}
1123											(true, Some(_)) => {
1124												synerr!('_', "OS command '{}' is disabled (restricted mode)", string_or_bytes(&word));
1125											},
1126											_ => {
1127												synerr!('_', "Invalid word command '{}'", string_or_bytes(&word));
1128											}
1129										}
1130									}
1131								}
1132							}
1133						},
1134						_ => unreachable!()
1135					}
1136				},
1137				ExecR => {
1138					let ri = if let Some(r) = rptr.take() {r}
1139					else {
1140						if matches!(mac.next().map(|b| {mac.back(); byte_cmd(b)}), None | Some(Space)) {
1141							synerr!(b as char, "No register index");
1142							alt = false;
1143							continue 'cmd;
1144						}
1145						Rational::from(
1146							match mac.try_next_char() {
1147								Ok(c) => {c as u32},
1148								Err(e) => {
1149									*count = Natural::ZERO;
1150									synerr!('\0', "Aborting invalid macro: {}", e);
1151									break 'cmd;
1152								}
1153							}
1154						)
1155					};
1156					debug!("Special register command {}{}", if alt {"alt-"} else {""}, b as char);
1157					match b {
1158						b'Z' => {	//stack depth
1159							push!(Value::N(
1160								st.regs.try_get(&ri).map(|reg| reg.v.len().into()).unwrap_or_default()
1161							));
1162						},
1163						b's' => {
1164							if let Some(va) = st.mstk.pop() {
1165								let reg = st.regs.get_mut(&ri);
1166								if let Some(rv) = reg.v.last_mut() {
1167									*rv = va;
1168								}
1169								else {
1170									reg.v.push(va);
1171								}
1172							}
1173							else {
1174								synerr!('s', "Stack is empty");
1175							}
1176						},
1177						b'S' => {
1178							if let Some(va) = st.mstk.pop() {
1179								st.regs.get_mut(&ri).v.push(va);
1180							}
1181							else {
1182								synerr!('S', "Stack is empty");
1183							}
1184						},
1185						b'l' => {
1186							if let Some(rv) = st.regs.try_get(&ri).and_then(|reg| reg.v.last()) {
1187								if let Some(p) = dest.last_mut() {	//manual shadowed push
1188									unsafe {
1189										p.as_mut().push((**rv).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
1190									}
1191								}
1192								else {
1193									st.mstk.push(Arc::clone(rv));
1194								}
1195							}
1196							else {
1197								synerr!('l', "Register {} is empty", reg_index_nice(&ri));
1198							}
1199						},
1200						b'L' => {
1201							if let Some(rv) = st.regs.try_get_mut(&ri).and_then(|reg| reg.v.pop()) {
1202								if let Some(p) = dest.last_mut() {	//manual shadowed push
1203									unsafe {
1204										p.as_mut().push((*rv).clone());	//SAFETY: `NonNull`s point to nested arrays in abuf, only one is accessed at a time
1205									}
1206								}
1207								else {
1208									st.mstk.push(Arc::clone(&rv));
1209								}
1210							}
1211							else {
1212								synerr!('L', "Register {} is empty", reg_index_nice(&ri));
1213							}
1214						},
1215						b'X' => {
1216							if let Some(true) = st.regs.try_get(&ri).map(|reg| reg.th.is_some()) {
1217								valerr!('X', "Register {} is already running a thread", reg_index_nice(&ri));
1218							}
1219							else if let Some(top) = st.mstk.pop() {
1220								let sec = st.mstk.pop();
1221								match Utf8Iter::from_vals(&top, sec.as_deref()) {
1222									Ok((stk, ret)) => {
1223										if let Some(sec) = sec && ret {	//sec was not used, return
1224											st.mstk.push(sec);
1225										}
1226
1227										let (tx, rx) = std::sync::mpsc::channel::<()>();
1228										let tb = std::thread::Builder::new().name(format!("{th_name}{}: ", reg_index_nice(&ri)));
1229										let mut th_st = if alt { st.clone() } else { State::default() };
1230										let th_io = Arc::clone(&io);
1231
1232										match tb.spawn(move || {
1233											let mut th_res = (Vec::new(), Ok(Finished));
1234
1235											'all: for (th_start, th_count) in stk {
1236												for _ in malachite::natural::exhaustive::exhaustive_natural_range(Natural::ZERO, th_count) {
1237													match interpreter_no_os(&mut th_st, th_start.clone(), Arc::clone(&th_io), ll, Some(&rx)) {
1238														Ok(Finished) => {continue;},
1239														Ok(er) => {
1240															th_res.1 = Ok(er);
1241															break 'all;
1242														},
1243														Err(e) => {
1244															th_res.1 = Err(e);
1245															break 'all;
1246														}
1247													}
1248												}
1249											}
1250
1251											th_res.0 = th_st.mstk;
1252											th_res
1253										}) {
1254											Ok(jh) => {
1255												st.regs.get_mut(&ri).th = Some((jh, tx));
1256											},
1257											Err(e) => {
1258												valerr!('X', "Can't spawn child thread: {}", e);
1259											}
1260										}
1261									},
1262									Err(e) => {
1263										if let Some(sec) = sec {st.mstk.push(sec);}
1264										st.mstk.push(top);
1265										synerr!('X', "{}", e);
1266									}
1267								}
1268							}
1269							else {
1270								synerr!('X', "Expected 1 or 2 arguments, 0 given");
1271							}
1272						},
1273						b'j' => {
1274							if let Some(reg) = st.regs.try_get_mut(&ri) && let Some((jh, tx)) = reg.th.take() {
1275								if alt {
1276									tx.send(()).unwrap_or_else(|_| panic!("Thread {} panicked, terminating!", reg_index_nice(&ri)));
1277								}
1278								match jh.join() {
1279									Ok(mut res) => {
1280										match res.1 {
1281											Err(e) => {
1282												valerr!('j', "IO error in thread {}: {}", reg_index_nice(&ri), e);
1283											},
1284											Ok(SoftQuit(c)) | Ok(HardQuit(c)) if c != 0 => {
1285												valerr!('j', "Thread {} exited with code {}", reg_index_nice(&ri), c);
1286											},
1287											_ => {}
1288										}
1289
1290										reg.v.append(&mut res.0);
1291									},
1292									Err(e) => {
1293										std::panic::resume_unwind(e);
1294									}
1295								}
1296							}
1297							else {
1298								valerr!('j', "Register {} is not running a thread", reg_index_nice(&ri));
1299							}
1300						},
1301						b'J' => {
1302							if let Some(Some((jh, _))) = st.regs.try_get(&ri).map(|reg| &reg.th) {
1303								let mut bz = BitVec::new();
1304								bz.push(jh.is_finished());
1305								push!(Value::B(bz));
1306							}
1307							else {
1308								valerr!('J', "Register {} is not running a thread", reg_index_nice(&ri));
1309							}
1310						},
1311						_ => unreachable!()
1312					}
1313				},
1314				Lit => {
1315					match b {
1316						b'T' | b'F' => {	//booleans
1317							debug!("Boolean literal");
1318							let mut bits = BitVec::new();
1319							bits.push(b == b'T');
1320							while let Some(b) = mac.next() {
1321								match b {
1322									b'T' => {bits.push(true);},
1323									b'F' => {bits.push(false);},
1324									_ => {
1325										mac.back();
1326										break;
1327									}
1328								}
1329							}
1330							push!(Value::B(bits));
1331						},
1332						b'\'' | b'0'..=b'9' | b'.' | b'@' => {	//numbers
1333							debug!("Number literal");
1334							let mut ipart = Vec::new();
1335							let mut fpart = Vec::new();
1336							let mut rpart = Vec::new();
1337							let mut get_epart = true;
1338							let mut exp = None;
1339							let mut discard = false;
1340							let mut ibase = st.params.get_i().clone();
1341
1342							match (b == b'\'', ibase > Natural::const_from(36)) {
1343								(false, high_base) => {	//plain
1344									mac.back();
1345									ibase = if high_base {Natural::const_from(10)} else {ibase};	//if plain but I>36, interpret mantissa with I=10
1346									while let Some(ib) = mac.next() {	//integer part
1347										let id = ib.wrapping_sub(0x30);
1348										match id {
1349											0..=9 if id < ibase => {ipart.push(Natural::from(id));},
1350											0..=9 => {
1351												synerr!('\'', "Digit {} is too high for base {}", id, ibase);
1352												discard = true;
1353											},
1354											_ => {
1355												mac.back();
1356												break;
1357											}
1358										}
1359									}
1360									match mac.next() {
1361										Some(b'.') => {	//fractional part
1362											let mut recur = false;	//recurring digits started
1363											while let Some(fb) = mac.next() {
1364												let fd = fb.wrapping_sub(0x30);
1365												match fd {
1366													0x30 if !recur => {recur = true;},	//b'`' == 0x60
1367													0..=9 if !recur && fd < ibase => {fpart.push(Natural::from(fd));},
1368													0..=9 if recur && fd < ibase => {rpart.push(Natural::from(fd));},
1369													0..=9 => {
1370														synerr!('\'', "Digit {} is too high for base {}", fd, ibase);
1371														discard = true;
1372													},
1373													_ => {
1374														mac.back();
1375														break;
1376													}
1377												}
1378											}
1379										},
1380										Some(_) => {mac.back();},
1381										None => {}
1382									}
1383								}
1384								(true, false) => {	//prefixed
1385									while let Some(ib) = mac.next() {	//integer part
1386										if let Some(id) = mixed_ascii_to_digit(ib) {
1387											if id < ibase {ipart.push(Natural::from(id));}
1388											else {
1389												synerr!('\'', "Digit {} is too high for base {}", id, ibase);
1390												discard = true;
1391											}
1392										}
1393										else {
1394											mac.back();
1395											break;
1396										}
1397									}
1398									match mac.next() {
1399										Some(b'.') => {	//fractional part
1400											let mut recur = false;	//recurring digits started
1401											while let Some(fb) = mac.next() {
1402												if let Some(fd) = mixed_ascii_to_digit(fb) {
1403													if fd < ibase {
1404														if !recur {fpart.push(Natural::from(fd));}
1405														else {rpart.push(Natural::from(fd));}
1406													}
1407													else {
1408														synerr!('\'', "Digit {} is too high for base {}", fd, ibase);
1409														discard = true;
1410													}
1411												}
1412												else if !recur && fb == b'`' {recur = true;}
1413												else {
1414													mac.back();
1415													break;
1416												}
1417											}
1418										},
1419										Some(_) => {mac.back();},
1420										None => {}
1421									}
1422								},
1423								(true, true) => {	//enclosed
1424									get_epart = false;
1425									let ns= mac.by_ref().take_while(|b| *b != b'\'').collect::<Vec<u8>>();
1426									if ns.is_empty() {
1427										synerr!('\'', "Empty any-base number");
1428										alt = false;
1429										continue 'cmd;
1430									}
1431									for nc in ns.iter() {
1432										match nc {
1433											b' ' | b'.' | b'0'..=b'9' | b'@' | b'`' => {}	//fine
1434											wrong => {
1435												synerr!('\'', "Invalid character in any-base number: {}", string_or_bytes(&[*wrong]));
1436												alt = false;
1437												continue 'cmd;
1438											}
1439										}
1440									}
1441									let mut ms = Vec::new();
1442									match ns.split(|b| *b == b'@').collect::<Vec<&[u8]>>()[..] {
1443										[mpart] => {	//only mantissa
1444											ms = mpart.to_vec();
1445										},
1446										[mpart, epart] => {	//mantissa and exponent
1447											ms = mpart.to_vec();
1448											let mut es = epart.to_vec();
1449											if let Some(first) = es.first_mut() && *first == b'`' { *first = b'-'; }
1450											match String::from_utf8(es) {
1451												Ok(es) => {
1452													match es.parse::<i64>() {
1453														Ok(i) => { exp = Some(i); },
1454														Err(e) => {
1455															use std::num::IntErrorKind::*;
1456															match e.kind() {
1457																Empty => { exp = Some(0); },
1458																InvalidDigit => {
1459																	valerr!('\'', "Invalid exponent: {}", es);
1460																	alt = false;
1461																	continue 'cmd;
1462																},
1463																PosOverflow | NegOverflow => {
1464																	valerr!('\'', "Exponent {} is unrepresentable", es);
1465																	alt = false;
1466																	continue 'cmd;
1467																},
1468																_ => { unreachable!() }
1469															}
1470														}
1471													}
1472												},
1473												_ => { unreachable!() }
1474											}
1475										},
1476										ref v => {
1477											synerr!('\'', "{} exponent signs (@) in any-base number", v.len() - 1);
1478											drop(ms);
1479											alt = false;
1480											continue 'cmd;
1481										}
1482									}
1483									let mut is = Vec::new();
1484									let mut frs = Vec::new();
1485									match ms.split(|b| *b == b'.').collect::<Vec<&[u8]>>()[..] {
1486										[ipart] => {
1487											is = ipart.to_vec();
1488										},
1489										[ipart, fpart] => {
1490											is = ipart.to_vec();
1491											frs = fpart.to_vec();
1492										},
1493										ref v => {
1494											synerr!('\'', "{} fractional points (.) in any-base number", v.len() - 1);
1495											drop(is);
1496											alt = false;
1497											continue 'cmd;
1498										}
1499									}
1500									if is.contains(&b'`') {
1501										synerr!('\'', "Unexpected negative sign (`) in any-base number");
1502										alt = false;
1503										continue 'cmd;
1504									}
1505									let mut fs = Vec::new();
1506									let mut rs = Vec::new();
1507									match frs.split(|b| *b == b'`').collect::<Vec<&[u8]>>()[..] {
1508										[fpart] => {
1509											fs = fpart.to_vec();
1510										},
1511										[fpart, rpart] => {
1512											fs = fpart.to_vec();
1513											rs = rpart.to_vec();
1514										},
1515										ref v => {
1516											synerr!('\'', "{} recurring marks (`) in any-base number", v.len() - 1);
1517											drop(fs);
1518											alt = false;
1519											continue 'cmd;
1520										}
1521									}
1522									if !is.is_empty() { for id in is.split(|b| *b == b' ') {
1523										let id = str::from_utf8(id).unwrap();
1524										ipart.push(Natural::from_str(id).unwrap());
1525									}}
1526									if !fs.is_empty() { for fd in fs.split(|b| *b == b' ') {
1527										let fd = str::from_utf8(fd).unwrap();
1528										fpart.push(Natural::from_str(fd).unwrap());
1529									}}
1530									if !rs.is_empty() { for rd in rs.split(|b| *b == b' ') {
1531										let rd = str::from_utf8(rd).unwrap();
1532										rpart.push(Natural::from_str(rd).unwrap());
1533									}}
1534									for d in ipart.iter().chain(fpart.iter()).chain(rpart.iter()) {
1535										if *d >= ibase {
1536											synerr!('\'', "Digit {} is too high for base {}", d, ibase);
1537											alt = false;
1538											continue 'cmd;
1539										}
1540									}
1541								}
1542							}
1543
1544							let m_empty = ipart.is_empty() && fpart.is_empty() && rpart.is_empty();	//simpler const zero, also keep track of emptiness
1545							let mut r;
1546							if m_empty {
1547								r = Rational::ZERO;
1548							}
1549							else {
1550								ipart.reverse();	//malachite needs reverse order
1551								r = Rational::from_digits(&ibase, ipart, RationalSequence::from_vecs(fpart, rpart));
1552								if alt {r.neg_assign();}	//negative sign was set using alt
1553							}
1554
1555							if get_epart {
1556								match mac.next() {
1557									Some(b'@') => {    //exponent part
1558										let mut es = String::new();
1559										let mut eneg = false;    //negative sign occurred
1560										while let Some(eb) = mac.next() {
1561											match eb {
1562												b'`' if !eneg => { es.push('-'); }
1563												b'0'..=b'9' => { es.push(eb as char); }
1564												_ => {
1565													mac.back();
1566													break;
1567												}
1568											}
1569											eneg = true;    //only allow on first char
1570										}
1571										if es.is_empty() { es.push('0'); }
1572										if m_empty { r = Rational::ONE; }    //only exponent part present
1573										if let Ok(i) = es.parse::<i64>() {
1574											r *= Rational::from(st.params.get_i()).pow(i);    //apply exponent, get original ibase
1575										}
1576										else {
1577											valerr!('\'', "Exponent {} is unrepresentable", es);
1578											discard = true;
1579										}
1580									}
1581									Some(_) => { mac.back(); }
1582									None => {}
1583								}
1584							}
1585							else if let Some(i) = exp {
1586       							if m_empty { r = Rational::ONE; }    //only exponent part present
1587       							r *= Rational::from(ibase).pow(i);    //apply exponent
1588							}
1589
1590							if !discard {
1591								push!(Value::N(r));
1592							}
1593						},
1594						b'[' => {	//strings
1595							debug!("String literal");
1596							let mut bytes = Vec::new();
1597							let mut discard = false;
1598							let mut nest = 1usize;
1599							while let Some(b) = mac.next() {
1600								match b {
1601									b'[' => {
1602										nest = unsafe { nest.unchecked_add(1) };
1603										bytes.push(b'[');
1604									},
1605									b']' => {
1606										nest = unsafe { nest.unchecked_sub(1) };
1607										if nest == 0 {
1608											break;
1609										}
1610										else {
1611											bytes.push(b']');
1612										}
1613									},
1614									b'\\' => {	//character escapes
1615										match mac.next() {
1616											Some(b'a') => {bytes.push(0x07);},		//bell
1617											Some(b'b') => {bytes.push(0x08);},		//backspace
1618											Some(b't') => {bytes.push(0x09);},		//horizontal tab
1619											Some(b'n') => {bytes.push(0x0A);},		//line feed
1620											Some(b'v') => {bytes.push(0x0B);},		//vertical tab
1621											Some(b'f') => {bytes.push(0x0C);},		//form feed
1622											Some(b'r') => {bytes.push(0x0D);},		//carriage return
1623											Some(b'e') => {bytes.push(0x1B);},		//escape
1624											Some(b'[') => {bytes.push(b'[');},		//literal opening bracket
1625											Some(b']') => {bytes.push(b']');},		//literal closing bracket
1626											Some(b'\\') => {bytes.push(b'\\');},	//literal backslash
1627											Some(b0) => {							//other escapes
1628												if let Some(high) = upper_hex_to_nibble(b0) {	//byte literal
1629													if let Some(b1) = mac.next() {
1630														if let Some(low) = upper_hex_to_nibble(b1) {
1631															bytes.push(high << 4 | low);
1632														}
1633														else {
1634															synerr!('[', "Invalid byte escape: \\{}{}", b0 as char, b1 as char);
1635															discard = true;
1636														}
1637													}
1638													else {
1639														synerr!('[', "Incomplete byte escape: \\{}", b0 as char);
1640														discard = true;
1641													}
1642												}
1643												else {	//wrong escape
1644													mac.back();
1645													match mac.try_next_char() {
1646														Ok(c) => {
1647															synerr!('[', "Invalid character escape: \\{} (U+{:04X})", c, c as u32);
1648															discard = true;
1649														},
1650														Err(e) => {
1651															*count = Natural::ZERO;
1652															synerr!('\0', "Aborting invalid macro: {}", e);
1653															break 'cmd;
1654														}
1655													}
1656												}
1657											},
1658											None => {
1659												synerr!('[', "Incomplete character escape: \\");
1660												discard = true;
1661											}
1662										}
1663									},
1664									_ => {
1665										bytes.push(b);
1666									}
1667								}
1668							}
1669							if !discard {
1670								match String::try_from(Utf8Iter::from(bytes)) {
1671									Ok(s) => {
1672										push!(Value::S(s));
1673									},
1674									Err(e) => {
1675										synerr!('[', "Invalid string: {}", e);
1676									}
1677								}
1678							}
1679						},
1680						_ => unreachable!()
1681					}
1682				},
1683				Space if b == b'#' => {	//line comment
1684					debug!("Line comment");
1685					mac.find(|b| *b == b'\n');
1686				},
1687				Space => {
1688					//do nothing
1689				},
1690				Wrong => {
1691					mac.back();
1692					match mac.try_next_char() {
1693						Ok(c) => {
1694							synerr!(c, "Invalid command: {} (U+{:04X})", c, c as u32);
1695						},
1696						Err(e) => {
1697							*count = Natural::ZERO;
1698							synerr!('\0', "Aborting invalid macro: {}", e);
1699							break 'cmd;
1700						}
1701					}
1702				}
1703			}
1704			
1705			alt = false;	//reset after digraph
1706		}	//end of command scope
1707
1708		if !dest.is_empty() {	//flush array buffer if not completed
1709			st.mstk.push(Arc::new(Value::A(std::mem::take(&mut abuf))));
1710			dest.clear();	//SAFETY: remove leftover dangling references
1711		}
1712
1713		if *count == Natural::ZERO {	//all repetitions finished
1714			call.pop();
1715		}
1716		else {	//more to go
1717			mac.rewind();
1718		}
1719	}	//end of macro scope
1720	
1721	Ok(Finished)
1722}