adc_lang/
lib.rs

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