Skip to main content

adc_lang/
lib.rs

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