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