diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 307fe119..bd8effaa 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -24,6 +24,7 @@ jobs: - run: RUSTFLAGS="-D warnings" cargo check --all-targets - run: RUSTFLAGS="-D warnings" cargo check --all-targets --features trace - run: RUSTFLAGS="-D warnings" cargo check --all-targets --features _fuzz + - run: RUSTFLAGS="-D warnings" cargo check --all-targets --no-default-features test: runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/Cargo.lock b/Cargo.lock index 0fe98f1d..cddf0e1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -302,6 +302,7 @@ dependencies = [ "clap", "insta", "nohash-hasher", + "parking_lot", "serial_test", "stacker", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 4fc7c8fc..3ecdac5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ TSPL = "0.0.9" arrayvec = "0.7.4" clap = { version = "4.5.1", features = ["derive"], optional = true } nohash-hasher = { version = "0.2.0" } +parking_lot = "0.12.1" stacker = "0.1.15" thiserror = "1.0.58" @@ -35,10 +36,11 @@ thiserror = "1.0.58" [features] default = ["cli", "_full_cli"] -cli = ["dep:clap"] +std = [] +cli = ["std", "dep:clap"] trace = [] _full_cli = [] -_fuzz = [] +_fuzz = ["std"] _fuzz_no_free = ["_fuzz"] [dev-dependencies] diff --git a/src/ast.rs b/src/ast.rs index b45e3b66..2f45e723 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -10,14 +10,16 @@ //! //! [interaction calculus]: https://en.wikipedia.org/wiki/Interaction_nets#Interaction_calculus -use arrayvec::ArrayVec; +use crate::prelude::*; use crate::{ ops::Op, run::Lab, util::{array_vec, deref, maybe_grow}, }; -use std::{collections::BTreeMap, fmt, mem, str::FromStr}; +use alloc::collections::BTreeMap; +use arrayvec::ArrayVec; +use core::str::FromStr; use TSPL::{new_parser, Parser}; /// The top level AST node, representing a collection of named nets. @@ -147,10 +149,10 @@ pub const MAX_ADT_FIELDS: usize = MAX_ARITY - 1; impl Net { pub fn trees(&self) -> impl Iterator { - std::iter::once(&self.root).chain(self.redexes.iter().map(|(x, y)| [x, y]).flatten()) + iter::once(&self.root).chain(self.redexes.iter().map(|(x, y)| [x, y]).flatten()) } pub fn trees_mut(&mut self) -> impl Iterator { - std::iter::once(&mut self.root).chain(self.redexes.iter_mut().map(|(x, y)| [x, y]).flatten()) + iter::once(&mut self.root).chain(self.redexes.iter_mut().map(|(x, y)| [x, y]).flatten()) } } @@ -187,7 +189,7 @@ impl Tree { pub fn legacy_mat(mut arms: Tree, out: Tree) -> Option { let Tree::Ctr { lab: 0, ports } = &mut arms else { None? }; - let ports = std::mem::take(ports); + let ports = mem::take(ports); let Ok([zero, succ]) = <[_; 2]>::try_from(ports) else { None? }; let zero = Box::new(zero); let succ = Box::new(succ); @@ -513,6 +515,8 @@ impl Drop for Tree { #[test] fn test_tree_drop() { + use alloc::vec; + drop(Tree::from_str("((* (* *)) (* *))")); let mut long_tree = Tree::Era; diff --git a/src/compile.rs b/src/compile.rs index dae5eb9c..bb83d24c 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,12 +1,14 @@ +#![cfg(feature = "std")] + +use crate::prelude::*; + use crate::{ host::Host, run::{Instruction, InterpretedDef, LabSet, Port, Tag}, stdlib::HostedDef, }; -use std::{ - fmt::{self, Write}, - hash::{DefaultHasher, Hasher}, -}; +use core::hash::Hasher; +use std::{fmt::Write, hash::DefaultHasher}; /// Compiles a [`Host`] to Rust, returning a file to replace `gen.rs`. pub fn compile_host(host: &Host) -> String { diff --git a/src/fuzz.rs b/src/fuzz.rs index c283b2c7..ec3c519a 100644 --- a/src/fuzz.rs +++ b/src/fuzz.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "std")] //! An 'atomic fuzzer' to exhaustively test an atomic algorithm for correctness. //! //! This fuzzer can test an algorithm with every possible ordering of parallel @@ -69,14 +70,20 @@ //! algorithm is changed (particularly, the atomic instructions it executes), //! old paths may no longer be valid.) -use std::{ +use crate::prelude::*; + +use core::{ any::Any, cell::{OnceCell, RefCell}, fmt::Debug, marker::PhantomData, ops::Add, - sync::{atomic, Arc, Condvar, Mutex}, + sync::atomic, +}; +use std::{ + sync::{Arc, Condvar, Mutex}, thread::{self, Scope, ThreadId}, + thread_local, }; use nohash_hasher::IntMap; diff --git a/src/host.rs b/src/host.rs index 5aa28c89..479d3397 100644 --- a/src/host.rs +++ b/src/host.rs @@ -1,16 +1,15 @@ //! The runtime's host, which acts as a translation layer between the AST and //! the runtime. +use crate::prelude::*; + use crate::{ ast::{Book, Net, Tree}, run::{self, Addr, Def, Instruction, InterpretedDef, LabSet, Mode, Port, Tag, TrgId, Wire}, stdlib::HostedDef, util::create_var, }; -use std::{ - collections::{hash_map::Entry, HashMap}, - ops::{Deref, DerefMut, RangeFrom}, -}; +use core::ops::{Deref, DerefMut, RangeFrom}; mod calc_labels; mod encode; @@ -22,9 +21,9 @@ use calc_labels::calculate_label_sets; #[derive(Default)] pub struct Host { /// the forward mapping, from a name to the runtime def - pub defs: HashMap, + pub defs: Map, /// the backward mapping, from the address of a runtime def to the name - pub back: HashMap, + pub back: Map, } /// A potentially-owned reference to a [`Def`]. Vitally, the address of the @@ -63,8 +62,12 @@ impl Host { /// will be run when the name of a definition is not found in the book. /// The return value of the function will be inserted into the host. pub fn insert_book_with_default(&mut self, book: &Book, default_def: &mut dyn FnMut(&str) -> DefRef) { - self.defs.reserve(book.len()); - self.back.reserve(book.len()); + #[cfg(feature = "std")] + { + self.defs.reserve(book.len()); + self.back.reserve(book.len()); + } + // Because there may be circular dependencies, inserting the definitions // must be done in two phases: diff --git a/src/host/calc_labels.rs b/src/host/calc_labels.rs index 79e57ced..a521c5c0 100644 --- a/src/host/calc_labels.rs +++ b/src/host/calc_labels.rs @@ -1,6 +1,7 @@ -use crate::util::maybe_grow; +use crate::prelude::*; use super::*; +use crate::util::maybe_grow; /// Calculates the labels used in each definition of a book. /// @@ -76,7 +77,14 @@ use super::*; /// This algorithm runs in linear time (as refs are traversed at most twice), /// and requires no more space than the naive algorithm. pub(crate) fn calculate_label_sets<'b, 'l>(book: &'b Book, lookup: impl FnMut(&'b str) -> LabSet) -> LabelSets<'b> { - let mut state = State { book, lookup, labels: HashMap::with_capacity(book.len()) }; + let mut state = State { + book, + lookup, + #[cfg(feature = "std")] + labels: Map::with_capacity(book.len()), + #[cfg(not(feature = "std"))] + labels: Map::new(), + }; for name in book.keys() { state.visit_def(name, Some(0), None); @@ -85,7 +93,7 @@ pub(crate) fn calculate_label_sets<'b, 'l>(book: &'b Book, lookup: impl FnMut(&' LabelSets(state.labels) } -pub(crate) struct LabelSets<'b>(HashMap<&'b str, LabelState>); +pub(crate) struct LabelSets<'b>(Map<&'b str, LabelState>); impl<'b> LabelSets<'b> { pub(crate) fn into_iter(self) -> impl Iterator { @@ -99,7 +107,7 @@ impl<'b> LabelSets<'b> { struct State<'b, F> { book: &'b Book, lookup: F, - labels: HashMap<&'b str, LabelState>, + labels: Map<&'b str, LabelState>, } #[derive(Debug)] @@ -188,7 +196,7 @@ impl<'b, F: FnMut(&'b str) -> LabSet> State<'b, F> { #[test] fn test_calculate_labels() { - use std::collections::BTreeMap; + use alloc::collections::BTreeMap; assert_eq!( calculate_label_sets( &" diff --git a/src/host/encode.rs b/src/host/encode.rs index 1e2d6ff8..c7ca0c9d 100644 --- a/src/host/encode.rs +++ b/src/host/encode.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + use super::*; use crate::{ops::Op, run::Lab, util::maybe_grow}; @@ -33,7 +35,7 @@ impl Host { struct State<'a, E: Encoder> { host: &'a Host, encoder: &'a mut E, - scope: HashMap<&'a str, E::Trg>, + scope: Map<&'a str, E::Trg>, } impl<'a, E: Encoder> State<'a, E> { diff --git a/src/host/readback.rs b/src/host/readback.rs index d3665330..ffdd67b0 100644 --- a/src/host/readback.rs +++ b/src/host/readback.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + use super::*; use crate::util::maybe_grow; @@ -28,7 +30,7 @@ impl Host { /// See [`Host::readback`]. struct ReadbackState<'a> { host: &'a Host, - vars: HashMap, + vars: Map, var_id: RangeFrom, } diff --git a/src/lib.rs b/src/lib.rs index b38219eb..6fc67f4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,11 @@ #![feature(const_type_id, extern_types, inline_const, generic_const_exprs, new_uninit)] #![cfg_attr(feature = "trace", feature(const_type_name))] #![allow(non_snake_case, incomplete_features)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +mod prelude; pub mod ast; pub mod compile; diff --git a/src/main.rs b/src/main.rs index 90939e7d..0ba8e9bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,12 +10,13 @@ use hvmc::{ *, }; +use parking_lot::Mutex; use std::{ fs, io, path::Path, process::{self, Stdio}, str::FromStr, - sync::{Arc, Mutex}, + sync::Arc, time::{Duration, Instant}, }; @@ -236,7 +237,7 @@ fn reduce_exprs(host: Arc>, exprs: &[Net], opts: &RuntimeOpts) { for expr in exprs { let mut net = DynNet::new(&heap, opts.lazy_mode); dispatch_dyn_net!(&mut net => { - host.lock().unwrap().encode_net(net, Trg::port(run::Port::new_var(net.root.addr())), expr); + host.lock().encode_net(net, Trg::port(run::Port::new_var(net.root.addr())), expr); let start_time = Instant::now(); if opts.single_core { net.normal(); @@ -244,7 +245,7 @@ fn reduce_exprs(host: Arc>, exprs: &[Net], opts: &RuntimeOpts) { net.parallel_normal(); } let elapsed = start_time.elapsed(); - println!("{}", host.lock().unwrap().readback(net)); + println!("{}", host.lock().readback(net)); if opts.show_stats { print_stats(net, elapsed); } @@ -275,14 +276,14 @@ fn pretty_num(n: u64) -> String { } fn compile_executable(target: &str, host: Arc>) -> Result<(), io::Error> { - let gen = compile::compile_host(&host.lock().unwrap()); + let gen = compile::compile_host(&host.lock()); let outdir = ".hvm"; if Path::new(&outdir).exists() { fs::remove_dir_all(outdir)?; } let cargo_toml = include_str!("../Cargo.toml"); let mut cargo_toml = cargo_toml.split_once("##--COMPILER-CUTOFF--##").unwrap().0.to_owned(); - cargo_toml.push_str("[features]\ndefault = ['cli']\ncli = ['dep:clap']"); + cargo_toml.push_str("[features]\ndefault = ['cli']\ncli = ['std', 'dep:clap']\nstd = []"); macro_rules! include_files { ($([$($prefix:ident)*])? $mod:ident {$($sub:tt)*} $($rest:tt)*) => { @@ -316,6 +317,7 @@ fn compile_executable(target: &str, host: Arc>) -> Result<(), lib main ops + prelude run { addr allocator diff --git a/src/ops.rs b/src/ops.rs index dd13df77..590d13f5 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1,7 +1,8 @@ +use crate::prelude::*; + use crate::util::bi_enum; -use std::{ +use core::{ cmp::{Eq, Ord}, - fmt::Display, str::FromStr, }; @@ -163,8 +164,8 @@ pub struct Op { pub op: IntOp, } -impl Display for Op { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for Op { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.ty { Ty::U60 => write!(f, "{}", self.op), _ => write!(f, "{}.{}", self.ty, self.op), diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 00000000..43511de3 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,20 @@ +pub use alloc::{ + borrow::ToOwned, + boxed::Box, + format, + string::{String, ToString}, + vec, + vec::Vec, +}; +pub use core::{fmt, iter, mem, ptr}; + +#[cfg(feature = "std")] +pub use std::collections::{hash_map::Entry, HashMap as Map, HashSet as Set}; + +#[cfg(not(feature = "std"))] +pub use alloc::collections::{btree_map::Entry, BTreeMap as Map, BTreeSet as Set}; + +#[cfg(feature = "std")] +pub use std::error::Error; +#[cfg(feature = "std")] +pub use thiserror::Error; diff --git a/src/run.rs b/src/run.rs index 8e4ce9ed..751ac449 100644 --- a/src/run.rs +++ b/src/run.rs @@ -18,37 +18,36 @@ //! the principal port is left implicit //! - active pairs are thus stored in a dedicated vector, `net.redexes` +use crate::prelude::*; + use crate::{ ops::Op, trace, trace::Tracer, util::{bi_enum, deref}, }; -use nohash_hasher::{IntMap, IsEnabled}; -use std::{ - alloc::{self, Layout}, +use alloc::borrow::Cow; +use core::{ + alloc::Layout, any::{Any, TypeId}, - borrow::Cow, - fmt, hint::unreachable_unchecked, marker::PhantomData, mem::size_of, ops::{Add, AddAssign, Deref, DerefMut}, - sync::{Arc, Barrier}, - thread, }; +use nohash_hasher::{IntMap, IsEnabled}; #[cfg(feature = "_fuzz")] use crate::fuzz as atomic; #[cfg(not(feature = "_fuzz"))] -use std::sync::atomic; +use core::sync::atomic; #[cfg(feature = "_fuzz")] use crate::fuzz::spin_loop; #[cfg(not(feature = "_fuzz"))] fn spin_loop() {} // this could use `std::hint::spin_loop`, but in practice it hurts performance -use atomic::{AtomicU64, AtomicUsize, Ordering::Relaxed}; +use atomic::{AtomicU64, Ordering::Relaxed}; use Tag::*; diff --git a/src/run/allocator.rs b/src/run/allocator.rs index d0e5640a..ab6867f4 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -41,11 +41,11 @@ impl Heap { return None; } unsafe { - let ptr = alloc::alloc(Layout::array::(nodes).unwrap()) as *mut Node; + let ptr = alloc::alloc::alloc(Layout::array::(nodes).unwrap()) as *mut Node; if ptr.is_null() { return None; } - Some(Box::from_raw(core::ptr::slice_from_raw_parts_mut(ptr, nodes) as *mut _)) + Some(Box::from_raw(ptr::slice_from_raw_parts_mut(ptr, nodes) as *mut _)) } } } diff --git a/src/run/net.rs b/src/run/net.rs index 608eabbd..89a1a1e6 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -1,7 +1,7 @@ -use std::mem::MaybeUninit; - use super::*; +use mem::MaybeUninit; + /// An interaction combinator net. pub struct Net<'a, M: Mode> { pub(super) linker: Linker<'a, M>, @@ -16,7 +16,7 @@ deref!({<'a, M: Mode>} Net<'a, M> => self.linker: Linker<'a, M>); impl<'h, M: Mode> Net<'h, M> { /// Creates an empty net with a given heap. pub fn new(heap: &'h Heap) -> Self { - let mut net = Net::new_with_root(heap, Wire(std::ptr::null())); + let mut net = Net::new_with_root(heap, Wire(ptr::null())); net.root = Wire::new(net.alloc()); net } @@ -31,10 +31,10 @@ impl<'h, M: Mode> Net<'h, M> { } pub fn match_laziness_mut(&mut self) -> Result<&mut Net<'h, Lazy>, &mut Net<'h, Strict>> { - if M::LAZY { Ok(unsafe { core::mem::transmute(self) }) } else { Err(unsafe { core::mem::transmute(self) }) } + if M::LAZY { Ok(unsafe { mem::transmute(self) }) } else { Err(unsafe { mem::transmute(self) }) } } pub fn match_laziness(self) -> Result, Net<'h, Strict>> { - if M::LAZY { Ok(unsafe { core::mem::transmute(self) }) } else { Err(unsafe { core::mem::transmute(self) }) } + if M::LAZY { Ok(unsafe { mem::transmute(self) }) } else { Err(unsafe { mem::transmute(self) }) } } } @@ -135,7 +135,7 @@ impl<'h, M: Mode> Net<'h, M> { pub fn expand(&mut self) { assert!(!M::LAZY); let (new_root, out_port) = self.create_wire(); - let old_root = std::mem::replace(&mut self.root, new_root); + let old_root = mem::replace(&mut self.root, new_root); self.link_wire_port(old_root, ExpandDef::new(out_port)); } } diff --git a/src/run/parallel.rs b/src/run/parallel.rs index 65e4acf8..b1369ff2 100644 --- a/src/run/parallel.rs +++ b/src/run/parallel.rs @@ -1,3 +1,10 @@ +#![cfg(feature = "std")] + +use std::{sync::Barrier, thread}; + +use ::alloc::sync::Arc; +use atomic::AtomicUsize; + use super::*; impl<'h, M: Mode> Net<'h, M> { diff --git a/src/stdlib.rs b/src/stdlib.rs index 76147b38..4c861fb4 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -1,13 +1,13 @@ -use std::{ +use crate::prelude::*; + +use alloc::sync::Arc; +use core::{ marker::PhantomData, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, - }, + sync::atomic::{AtomicUsize, Ordering}, }; +use parking_lot::Mutex; use crate::{ - ast::Book, dispatch_dyn_net, host::{DefRef, Host}, run::{AsDef, Def, DynNetMut, LabSet, Mode, Net, Port, Tag, Trg}, @@ -48,7 +48,7 @@ impl AsHostedDef for LogDef { // SAFETY: the function inside `readback` won't live longer than // the net, and thus won't live longer than the host, where the // `&Def` points to - let def: &'static Def = unsafe { core::mem::transmute(def) }; + let def: &'static Def = unsafe { mem::transmute(def) }; readback(net, def.data.0.clone(), arg, |net, tree| { (def.data.1)(tree); dispatch_dyn_net!(net => { @@ -59,17 +59,18 @@ impl AsHostedDef for LogDef { } /// Create a `Host` from a `Book`, including `hvm-core`'s built-in definitions -pub fn create_host(book: &Book) -> Arc> { +#[cfg(feature = "std")] +pub fn create_host(book: &crate::ast::Book) -> Arc> { let host = Arc::new(Mutex::new(Host::default())); - host.lock().unwrap().insert_def("HVM.log", unsafe { + host.lock().insert_def("HVM.log", unsafe { crate::stdlib::LogDef::new(host.clone(), { move |tree| { println!("{}", tree); } }) }); - host.lock().unwrap().insert_def("HVM.black_box", DefRef::Static(unsafe { &*IDENTITY })); - host.lock().unwrap().insert_book(&book); + host.lock().insert_def("HVM.black_box", DefRef::Static(unsafe { &*IDENTITY })); + host.lock().insert_book(&book); host } @@ -210,7 +211,7 @@ impl AsBoxDef for ReadbackDef { (*other.data.0.tree.0) = var; } Self::maybe_finish(DynNetMut::from(&mut *net), other.data.0.root); - } else if let Some(back) = def.data.host.lock().unwrap().back.get(&port.addr()) { + } else if let Some(back) = def.data.host.lock().back.get(&port.addr()) { unsafe { *(def.data.tree.0) = Tree::Ref { nam: back.clone() } }; } else { unsafe { *(def.data.tree.0) = Tree::Era }; @@ -270,7 +271,7 @@ pub fn readback( if M::LAZY { let from = net.wire_to_trg(from); net.normal_from(from.clone()); - let tree = host.lock().unwrap().readback_tree(&from); + let tree = host.lock().readback_tree(&from); net.link_wire_port(from, Port::ERA); f(DynNetMut::from(net), tree); } else { diff --git a/src/trace.rs b/src/trace.rs index 8905d1cb..466e3901 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -63,14 +63,14 @@ #![cfg_attr(not(feature = "trace"), allow(unused))] -use std::{ +use crate::prelude::*; + +use core::{ cell::UnsafeCell, fmt::{self, Debug, Formatter, Write}, - sync::{ - atomic::{AtomicBool, AtomicU64, Ordering}, - Mutex, Once, - }, + sync::atomic::{AtomicBool, AtomicU64, Ordering}, }; +use parking_lot::{Mutex, Once}; use crate::{ ops::Op, @@ -195,7 +195,7 @@ impl Default for TraceWriter { data: UnsafeCell::new(TraceData { tid: 0, cursor: 0, data: Box::new([0; TRACE_SIZE]) }), }); let lock = unsafe { &*(&*boxed as *const _) }; - let mut active_tracers = ACTIVE_TRACERS.lock().unwrap(); + let mut active_tracers = ACTIVE_TRACERS.lock(); active_tracers.push(boxed); TraceWriter { lock, nonce: TRACE_NONCE.fetch_add(1, Ordering::Relaxed) } } @@ -207,7 +207,7 @@ impl TraceWriter { } fn acquire(&self, cb: impl FnOnce(&mut TraceData)) { while self.lock.locked.compare_exchange_weak(false, true, Ordering::Relaxed, Ordering::Relaxed).is_err() { - std::hint::spin_loop(); + core::hint::spin_loop(); } cb(unsafe { &mut *self.lock.data.get() }); self.lock.locked.store(false, Ordering::Release); @@ -291,14 +291,15 @@ impl<'a> TraceReader<'a> { } #[cfg_attr(feature = "trace", no_mangle)] +#[cfg(feature = "std")] pub fn _read_traces(limit: usize) { - let active_tracers = &*ACTIVE_TRACERS.lock().unwrap(); + let active_tracers = &*ACTIVE_TRACERS.lock(); let mut readers = active_tracers .iter() .enumerate() .map(|(i, t)| { while t.locked.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() { - std::hint::spin_loop(); + core::hint::spin_loop(); } TraceReader::new(unsafe { &*t.data.get() }, i) }) @@ -314,7 +315,7 @@ pub fn _read_traces(limit: usize) { } pub unsafe fn _reset_traces() { - ACTIVE_TRACERS.lock().unwrap().clear(); + ACTIVE_TRACERS.lock().clear(); TRACE_NONCE.store(1, Ordering::Relaxed); } @@ -462,6 +463,7 @@ impl fmt::Debug for FmtWord { pub fn set_hook() { static ONCE: Once = Once::new(); if cfg!(feature = "trace") { + #[cfg(feature = "std")] ONCE.call_once(|| { let hook = std::panic::take_hook(); std::panic::set_hook(Box::new(move |info| { diff --git a/src/transform.rs b/src/transform.rs index 023aed19..2bd2c95b 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,6 +1,6 @@ -use thiserror::Error; +use crate::prelude::*; -use crate::{ast::Book, util}; +use crate::ast::Book; pub mod coalesce_ctrs; pub mod encode_adts; @@ -9,10 +9,11 @@ pub mod inline; pub mod pre_reduce; pub mod prune; -#[derive(Debug, Error, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] +#[cfg_attr(feature = "std", derive(Error))] pub enum TransformError { - #[error("infinite reference cycle in `@{0}`")] + #[cfg_attr(feature = "std", error("infinite reference cycle in `@{0}`"))] InfiniteRefCycle(String), } @@ -90,13 +91,13 @@ pub struct TransformOpts { /// How much memory to allocate when pre-reducing. /// /// Supports abbreviations such as '4G' or '400M'. - #[cfg_attr(feature = "cli", arg(long = "pre-reduce-memory", value_parser = util::parse_abbrev_number::))] + #[cfg_attr(feature = "cli", arg(long = "pre-reduce-memory", value_parser = crate::util::parse_abbrev_number::))] pub pre_reduce_memory: Option, /// Maximum amount of rewrites to do when pre-reducing. /// /// Supports abbreviations such as '4G' or '400M'. - #[cfg_attr(feature = "cli", arg(long = "pre-reduce-rewrites", default_value = "100M", value_parser = util::parse_abbrev_number::))] + #[cfg_attr(feature = "cli", arg(long = "pre-reduce-rewrites", default_value = "100M", value_parser = crate::util::parse_abbrev_number::))] pub pre_reduce_rewrites: u64, /// Names of the definitions that should not get pruned. diff --git a/src/transform/coalesce_ctrs.rs b/src/transform/coalesce_ctrs.rs index 0b201171..aeb0cf3a 100644 --- a/src/transform/coalesce_ctrs.rs +++ b/src/transform/coalesce_ctrs.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + use crate::{ ast::{Tree, MAX_ARITY}, util::maybe_grow, @@ -16,7 +18,7 @@ impl Tree { { ports.extend(inner_ports.drain(..)); } - Some(other) => ports.push(std::mem::take(other)), + Some(other) => ports.push(mem::take(other)), None => (), } } diff --git a/src/transform/encode_adts.rs b/src/transform/encode_adts.rs index c492991d..509a4b5d 100644 --- a/src/transform/encode_adts.rs +++ b/src/transform/encode_adts.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + use crate::{ ast::{Tree, MAX_ADT_VARIANTS}, util::maybe_grow, @@ -38,7 +40,7 @@ impl Tree { let fields = match &mut ports.swap_remove(idx) { Tree::Ctr { ports: fields, .. } => { fields.pop(); - std::mem::take(fields) + mem::take(fields) } Tree::Var { .. } => vec![], _ => unreachable!(), diff --git a/src/transform/eta_reduce.rs b/src/transform/eta_reduce.rs index 11745145..57c39c6f 100644 --- a/src/transform/eta_reduce.rs +++ b/src/transform/eta_reduce.rs @@ -53,9 +53,10 @@ //! //! The pass also reduces subnets such as `(* *) -> *` -use std::{collections::HashMap, ops::RangeFrom}; +use crate::prelude::*; use crate::ast::{Net, Tree}; +use core::ops::RangeFrom; impl Net { /// Carries out simple eta-reduction @@ -83,7 +84,7 @@ enum NodeType { #[derive(Default)] struct Phase1<'a> { - vars: HashMap<&'a str, usize>, + vars: Map<&'a str, usize>, nodes: Vec, } diff --git a/src/transform/inline.rs b/src/transform/inline.rs index 54875529..704ba91d 100644 --- a/src/transform/inline.rs +++ b/src/transform/inline.rs @@ -1,20 +1,17 @@ -use std::{ - collections::{HashMap, HashSet}, - ops::BitOr, -}; +use crate::prelude::*; +use super::TransformError; use crate::{ ast::{Book, Net, Tree}, util::maybe_grow, }; - -use super::TransformError; +use core::ops::BitOr; impl Book { - pub fn inline(&mut self) -> Result, TransformError> { + pub fn inline(&mut self) -> Result, TransformError> { let mut state = InlineState::default(); state.populate_inlinees(self)?; - let mut all_changed = HashSet::new(); + let mut all_changed = Set::new(); for (name, net) in &mut self.nets { let mut inlined = false; for tree in net.trees_mut() { @@ -30,7 +27,7 @@ impl Book { #[derive(Debug, Default)] struct InlineState { - inlinees: HashMap, + inlinees: Map, } impl InlineState { diff --git a/src/transform/pre_reduce.rs b/src/transform/pre_reduce.rs index 4e41df00..84855611 100644 --- a/src/transform/pre_reduce.rs +++ b/src/transform/pre_reduce.rs @@ -14,10 +14,7 @@ //! At the end, each mutated [`ast::Net`] is placed into the [`Book`], //! overriding the previous one. -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; +use crate::prelude::*; use crate::{ ast::{Book, Net, Tree}, @@ -26,6 +23,8 @@ use crate::{ stdlib::{AsHostedDef, HostedDef}, util::maybe_grow, }; +use alloc::sync::Arc; +use parking_lot::Mutex; impl Book { /// Reduces the definitions in the book individually, except for the skipped @@ -55,7 +54,7 @@ impl Book { max_rwts, host, area: &area, - seen: HashMap::new(), + seen: Map::new(), rewrites: Rewrites::default(), }; @@ -96,7 +95,7 @@ struct InertDef(Arc>>); impl AsHostedDef for InertDef { fn call(def: &run::Def, _: &mut run::Net, port: run::Port) { - def.data.0.lock().unwrap().push((run::Port::new_ref(def), port)); + def.data.0.lock().push((run::Port::new_ref(def), port)); } } @@ -111,7 +110,7 @@ struct State<'a> { captured_redexes: Arc>>, skip: &'a dyn Fn(&str) -> bool, - seen: HashMap, + seen: Map, rewrites: Rewrites, } @@ -148,7 +147,7 @@ impl<'a> State<'a> { self.rewrites += rt.rwts; // Move interactions with inert defs back into the net redexes array - self.captured_redexes.lock().unwrap().drain(..).for_each(|r| rt.redux(r.0, r.1)); + self.captured_redexes.lock().drain(..).for_each(|r| rt.redux(r.0, r.1)); let net = self.host.readback(&mut rt); diff --git a/src/transform/prune.rs b/src/transform/prune.rs index 9577a17f..c7f8c926 100644 --- a/src/transform/prune.rs +++ b/src/transform/prune.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use crate::prelude::*; use crate::{ ast::{Book, Tree}, @@ -21,7 +21,7 @@ impl Book { #[derive(Debug)] struct PruneState<'a> { book: &'a Book, - unvisited: HashSet, + unvisited: Set, } impl<'a> PruneState<'a> { diff --git a/src/util/apply_tree.rs b/src/util/apply_tree.rs index 61dd221e..772f4fe1 100644 --- a/src/util/apply_tree.rs +++ b/src/util/apply_tree.rs @@ -1,6 +1,7 @@ -use crate::ast::{Net, Tree}; +use crate::prelude::*; use super::{create_var, var_to_num}; +use crate::ast::{Net, Tree}; impl Net { /// Transforms the net `x & ...` into `y & x ~ (arg y) & ...` @@ -15,7 +16,7 @@ impl Net { let fresh_str = create_var(fresh + 1); - let fun = core::mem::take(&mut self.root); + let fun = mem::take(&mut self.root); let app = Tree::Ctr { lab: 0, ports: vec![arg, Tree::Var { nam: fresh_str.clone() }] }; self.root = Tree::Var { nam: fresh_str }; self.redexes.push((fun, app)); diff --git a/src/util/bi_enum.rs b/src/util/bi_enum.rs index faaf0b0f..541338b5 100644 --- a/src/util/bi_enum.rs +++ b/src/util/bi_enum.rs @@ -36,13 +36,13 @@ macro_rules! bi_enum { ) => { bi_enum! { #[repr($uN)] $(#$attr)* $vis enum $Ty { $($(#$var_addr)* $Variant = $value,)* } } - impl std::fmt::Display for $Ty { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + impl core::fmt::Display for $Ty { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str(match self { $($Ty::$Variant => $str,)* }) } } - impl std::str::FromStr for $Ty { + impl core::str::FromStr for $Ty { type Err = (); fn from_str(s: &str) -> Result { Ok(match s { $($str => $Ty::$Variant,)* _ => Err(())?, }) @@ -55,7 +55,9 @@ pub(crate) use bi_enum; #[test] fn test_bi_enum() { - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; + bi_enum! { #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/util/create_var.rs b/src/util/create_var.rs index 4f6012e1..5a4725a9 100644 --- a/src/util/create_var.rs +++ b/src/util/create_var.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + /// Creates a variable uniquely identified by `id`. pub(crate) fn create_var(mut id: usize) -> String { let mut txt = Vec::new(); diff --git a/src/util/deref.rs b/src/util/deref.rs index 6774a072..a0bac15e 100644 --- a/src/util/deref.rs +++ b/src/util/deref.rs @@ -1,12 +1,12 @@ macro_rules! deref { ($({$($gen:tt)*})? $ty:ty => self.$field:ident: $trg:ty) => { - impl $($($gen)*)? std::ops::Deref for $ty { + impl $($($gen)*)? core::ops::Deref for $ty { type Target = $trg; fn deref(&self) -> &Self::Target { &self.$field } } - impl $($($gen)*)? std::ops::DerefMut for $ty { + impl $($($gen)*)? core::ops::DerefMut for $ty { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.$field } diff --git a/src/util/parse_abbrev_number.rs b/src/util/parse_abbrev_number.rs index ede54401..edbbf013 100644 --- a/src/util/parse_abbrev_number.rs +++ b/src/util/parse_abbrev_number.rs @@ -1,8 +1,10 @@ +use crate::prelude::*; + /// Turn a string representation of a number, such as '1G' or '400K', into a /// number. pub fn parse_abbrev_number>(arg: &str) -> Result where - >::Error: core::fmt::Debug, + >::Error: fmt::Debug, { let (base, scale) = match arg.to_lowercase().chars().last() { None => return Err("Mem size argument is empty".to_string()), diff --git a/src/util/stats.rs b/src/util/stats.rs index 4e6552e3..fa88c598 100644 --- a/src/util/stats.rs +++ b/src/util/stats.rs @@ -1,4 +1,6 @@ -use std::time::Duration; +use crate::prelude::*; + +use core::time::Duration; use crate::run::Rewrites; @@ -28,7 +30,7 @@ fn pretty_num(n: u64) -> String { .as_bytes() .rchunks(3) .rev() - .map(|x| std::str::from_utf8(x).unwrap()) + .map(|x| core::str::from_utf8(x).unwrap()) .flat_map(|x| ["_", x]) .skip(1) .collect() diff --git a/tests/lists.rs b/tests/lists.rs index 69b26eda..f1dcfe2f 100644 --- a/tests/lists.rs +++ b/tests/lists.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "std")] + use crate::loaders::*; use hvmc::ast::Book; use insta::assert_debug_snapshot; diff --git a/tests/loaders/mod.rs b/tests/loaders/mod.rs index 90737128..e97434a7 100644 --- a/tests/loaders/mod.rs +++ b/tests/loaders/mod.rs @@ -27,10 +27,10 @@ pub fn normal_with(book: Book, mem: Option, entry_point: &str) -> (hvmc:: let host = create_host(&book); let mut rnet = run::Net::::new(&area); - rnet.boot(&host.lock().unwrap().defs[entry_point]); + rnet.boot(&host.lock().defs[entry_point]); rnet.normal(); - let net = host.lock().unwrap().readback(&rnet); + let net = host.lock().readback(&rnet); (rnet.rwts, net) } diff --git a/tests/tests.rs b/tests/tests.rs index df166419..bbde5091 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,9 +1,12 @@ +#![cfg(feature = "std")] + +use parking_lot::Mutex; use std::{ fs, io::{self, Write}, path::{Path, PathBuf}, str::FromStr, - sync::{Arc, Mutex}, + sync::Arc, time::Instant, }; @@ -65,7 +68,7 @@ fn execute_host(host: Arc>) -> Option<(run::Rewrites, Net)> { let mut net = run::Net::::new(&heap); // The host is locked inside this block. { - let lock = host.lock().unwrap(); + let lock = host.lock(); let Some(entrypoint) = lock.defs.get("main") else { println!(" skipping"); return None; @@ -75,7 +78,7 @@ fn execute_host(host: Arc>) -> Option<(run::Rewrites, Net)> { let start = Instant::now(); net.parallel_normal(); println!(" {:.3?}", start.elapsed()); - Some((net.rwts, host.lock().unwrap().readback(&net))) + Some((net.rwts, host.lock().readback(&net))) } fn test_run(name: &str, host: Arc>) { diff --git a/tests/transform.rs b/tests/transform.rs index dba7a227..25247af5 100644 --- a/tests/transform.rs +++ b/tests/transform.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "std")] + //! Tests for transformation passes pub mod loaders;