From 54cf65f53cf15add868bc504c89bbdd5686d7160 Mon Sep 17 00:00:00 2001 From: imaqtkatt <135721694+imaqtkatt@users.noreply.github.com> Date: Tue, 9 Apr 2024 10:56:50 -0300 Subject: [PATCH 1/5] Expose normal_from and is_full_node (#116) --- src/run/net.rs | 2 +- src/run/port.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/run/net.rs b/src/run/net.rs index a81dc3d6..608eabbd 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -60,7 +60,7 @@ impl<'a, M: Mode> Net<'a, M> { // Lazy mode weak head normalizer #[inline(always)] - fn weak_normal(&mut self, mut prev: Port, root: Wire) -> Port { + pub fn weak_normal(&mut self, mut prev: Port, root: Wire) -> Port { assert!(M::LAZY); let mut path: Vec = vec![]; diff --git a/src/run/port.rs b/src/run/port.rs index d0f2eac5..83d58b19 100644 --- a/src/run/port.rs +++ b/src/run/port.rs @@ -208,7 +208,7 @@ impl Port { Port::new(Var, 0, self.addr()) } - pub(super) fn is_full_node(&self) -> bool { + pub fn is_full_node(&self) -> bool { self.tag() > Num } } From d0d92bad7ce9ad9fa2ace3351f96bfa18c65ba99 Mon Sep 17 00:00:00 2001 From: T6 Date: Tue, 9 Apr 2024 17:04:11 -0400 Subject: [PATCH 2/5] use tspl for parser (#122) --- Cargo.lock | 16 ++++++ Cargo.toml | 1 + cspell.json | 1 + src/ast.rs | 138 ++++++++++++---------------------------------------- 4 files changed, 50 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df6e4aa4..0fe98f1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "TSPL" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9423b1e6e2d6c0bbc03660f58f9c30f55359e13afea29432e6e767c0f7dc25" +dependencies = [ + "highlight_error", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -278,10 +287,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "highlight_error" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e18805660d7b6b2e2b9f316a5099521b5998d5cba4dda11b5157a21aaef03" + [[package]] name = "hvm-core" version = "0.2.24" dependencies = [ + "TSPL", "arrayvec", "clap", "insta", diff --git a/Cargo.toml b/Cargo.toml index e3263181..907a31c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ panic = "abort" debug = "full" [dependencies] +TSPL = "0.0.9" arrayvec = "0.7.4" clap = { version = "4.5.1", features = ["derive"] } nohash-hasher = { version = "0.2.0" } diff --git a/cspell.json b/cspell.json index cf626b3d..d6033f97 100644 --- a/cspell.json +++ b/cspell.json @@ -58,6 +58,7 @@ "tids", "tlog", "trgs", + "tspl", "trit", "uninit", "unioned", diff --git a/src/ast.rs b/src/ast.rs index be7c6987..b45e3b66 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -18,6 +18,7 @@ use crate::{ util::{array_vec, deref, maybe_grow}, }; use std::{collections::BTreeMap, fmt, mem, str::FromStr}; +use TSPL::{new_parser, Parser}; /// The top level AST node, representing a collection of named nets. /// @@ -194,13 +195,9 @@ impl Tree { } } -/// The state of the HVMC parser. -struct Parser<'i> { - /// The remaining characters in the input. An empty string indicates EOF. - input: &'i str, -} +new_parser!(HvmcParser); -impl<'i> Parser<'i> { +impl<'i> HvmcParser<'i> { /// Book = ("@" Name "=" Net)* fn parse_book(&mut self) -> Result { maybe_grow(move || { @@ -231,19 +228,19 @@ impl<'i> Parser<'i> { fn parse_tree(&mut self) -> Result { maybe_grow(move || { self.skip_trivia(); - match self.peek_char() { + match self.peek_one() { // Era = "*" Some('*') => { - self.advance_char(); + self.advance_one(); Ok(Tree::Era) } // Ctr = "(" Tree Tree ")" | "[" Tree Tree "]" | "{" Int Tree Tree "}" Some(char @ ('(' | '[' | '{')) => { - self.advance_char(); + self.advance_one(); let lab = match char { '(' => 0, '[' => 1, - '{' => self.parse_int()? as Lab, + '{' => self.parse_u64()? as Lab, _ => unreachable!(), }; let close = match char { @@ -253,18 +250,18 @@ impl<'i> Parser<'i> { _ => unreachable!(), }; self.skip_trivia(); - if self.peek_char().is_some_and(|x| x == ':') { - self.advance_char(); - let variant_index = self.parse_int()?; + if self.peek_one().is_some_and(|x| x == ':') { + self.advance_one(); + let variant_index = self.parse_u64()?; self.consume(":")?; - let variant_count = self.parse_int()?; + let variant_count = self.parse_u64()?; let mut fields = Vec::new(); self.skip_trivia(); - while self.peek_char() != Some(close) { + while self.peek_one() != Some(close) { fields.push(self.parse_tree()?); self.skip_trivia(); } - self.advance_char(); + self.advance_one(); if variant_count == 0 { Err("variant count cannot be zero".to_owned())?; } @@ -283,11 +280,11 @@ impl<'i> Parser<'i> { } else { let mut ports = Vec::new(); self.skip_trivia(); - while self.peek_char() != Some(close) { + while self.peek_one() != Some(close) { ports.push(self.parse_tree()?); self.skip_trivia(); } - self.advance_char(); + self.advance_one(); if ports.len() > MAX_ARITY { Err("ctr has too many ports".to_owned())?; } @@ -296,25 +293,25 @@ impl<'i> Parser<'i> { } // Ref = "@" Name Some('@') => { - self.advance_char(); + self.advance_one(); self.skip_trivia(); let nam = self.parse_name()?; Ok(Tree::Ref { nam }) } // Num = "#" Int Some('#') => { - self.advance_char(); - match self.peek_char() { + self.advance_one(); + match self.peek_one() { Some('-') => { - self.advance_char(); - Ok(Tree::Num { val: -(self.parse_int()? as i64) }) + self.advance_one(); + Ok(Tree::Num { val: -(self.parse_u64()? as i64) }) } - _ => Ok(Tree::Num { val: self.parse_int()? as i64 }), + _ => Ok(Tree::Num { val: self.parse_u64()? as i64 }), } } // Op = "<" Op Tree Tree ">" Some('<') => { - self.advance_char(); + self.advance_one(); let op = self.parse_op()?; let rhs = Box::new(self.parse_tree()?); let out = Box::new(self.parse_tree()?); @@ -323,13 +320,13 @@ impl<'i> Parser<'i> { } // Mat = "?<" Tree Tree ">" Some('?') => { - self.advance_char(); + self.advance_one(); self.consume("<")?; let zero = self.parse_tree()?; let succ = self.parse_tree()?; self.skip_trivia(); - if self.peek_char() == Some('>') { - self.advance_char(); + if self.peek_one() == Some('>') { + self.advance_one(); Tree::legacy_mat(zero, succ).ok_or_else(|| "invalid legacy match".to_owned()) } else { let zero = Box::new(zero); @@ -349,95 +346,24 @@ impl<'i> Parser<'i> { fn parse_name(&mut self) -> Result { let name = self.take_while(|c| c.is_alphanumeric() || c == '_' || c == '.' || c == '$'); if name.is_empty() { - return Err(format!("Expected a name character, found {:?}", self.peek_char())); + return self.expected("name"); } Ok(name.to_owned()) } - /// Int = /[0-9]+/ | /0x[0-9a-fA-F]+/ | /0b[01]+/ - fn parse_int(&mut self) -> Result { - self.skip_trivia(); - let radix = if let Some(rest) = self.input.strip_prefix("0x") { - self.input = rest; - 16 - } else if let Some(rest) = self.input.strip_prefix("0b") { - self.input = rest; - 2 - } else { - 10 - }; - let mut num: u64 = 0; - if !self.peek_char().map_or(false, |c| c.is_digit(radix)) { - return Err(format!("Expected a digit, found {:?}", self.peek_char())); - } - while let Some(digit) = self.peek_char().and_then(|c| c.to_digit(radix)) { - self.advance_char(); - num = num * (radix as u64) + (digit as u64); - } - Ok(num) - } - /// See `ops.rs` for the available operators. fn parse_op(&mut self) -> Result { let op = self.take_while(|c| "ui0123456789.+-=*/%<>|&^!?$".contains(c)); op.parse().map_err(|_| format!("Unknown operator: {op:?}")) } - - /// Inspects the next character in the input without consuming it. - fn peek_char(&self) -> Option { - self.input.chars().next() - } - - /// Consumes the next character in the input. - fn advance_char(&mut self) -> Option { - let char = self.input.chars().next()?; - self.input = &self.input[char.len_utf8() ..]; - Some(char) - } - - /// Skips whitespace & comments in the input. - fn skip_trivia(&mut self) { - while let Some(c) = self.peek_char() { - if c.is_ascii_whitespace() { - self.advance_char(); - continue; - } - if c == '/' && self.input.starts_with("//") { - while self.peek_char() != Some('\n') { - self.advance_char(); - } - continue; - } - break; - } - } - - /// Consumes an instance of the given string, erroring if it is not found. - fn consume(&mut self, text: &str) -> Result<(), String> { - self.skip_trivia(); - let Some(rest) = self.input.strip_prefix(text) else { - return Err(format!("Expected {:?}, found {:?}", text, self.input.split_ascii_whitespace().next().unwrap_or(""))); - }; - self.input = rest; - Ok(()) - } - - /// Consumes all of the contiguous next characters in the input matching a - /// given predicate. - fn take_while(&mut self, mut f: impl FnMut(char) -> bool) -> &'i str { - let len = self.input.chars().take_while(|&c| f(c)).map(char::len_utf8).sum(); - let (name, rest) = self.input.split_at(len); - self.input = rest; - name - } } /// Parses the input with the callback, ensuring that the whole input is /// consumed. -fn parse_eof<'i, T>(input: &'i str, parse_fn: impl Fn(&mut Parser<'i>) -> Result) -> Result { - let mut parser = Parser { input }; +fn parse_eof<'i, T>(input: &'i str, parse_fn: impl Fn(&mut HvmcParser<'i>) -> Result) -> Result { + let mut parser = HvmcParser::new(input); let out = parse_fn(&mut parser)?; - if !parser.input.is_empty() { + if parser.index != parser.input.len() { return Err("Unable to parse the whole input. Is this not an hvmc file?".to_owned()); } Ok(out) @@ -446,21 +372,21 @@ fn parse_eof<'i, T>(input: &'i str, parse_fn: impl Fn(&mut Parser<'i>) -> Result impl FromStr for Book { type Err = String; fn from_str(str: &str) -> Result { - parse_eof(str, Parser::parse_book) + parse_eof(str, HvmcParser::parse_book) } } impl FromStr for Net { type Err = String; fn from_str(str: &str) -> Result { - parse_eof(str, Parser::parse_net) + parse_eof(str, HvmcParser::parse_net) } } impl FromStr for Tree { type Err = String; fn from_str(str: &str) -> Result { - parse_eof(str, Parser::parse_tree) + parse_eof(str, HvmcParser::parse_tree) } } From 40febf34ce6c6b09a249553574da9835cb1ca976 Mon Sep 17 00:00:00 2001 From: T6 Date: Wed, 10 Apr 2024 09:27:55 -0400 Subject: [PATCH 3/5] add `Book::transform` (#107) --- Cargo.toml | 6 +- src/main.rs | 205 +++++--------------------------- src/transform.rs | 165 +++++++++++++++++++++++++ src/util.rs | 2 + src/util/parse_abbrev_number.rs | 17 +++ 5 files changed, 215 insertions(+), 180 deletions(-) create mode 100644 src/util/parse_abbrev_number.rs diff --git a/Cargo.toml b/Cargo.toml index 907a31c5..4fc7c8fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" [[bin]] name = "hvmc" path = "src/main.rs" +required-features = ["cli"] bench = false [lib] @@ -25,7 +26,7 @@ debug = "full" [dependencies] TSPL = "0.0.9" arrayvec = "0.7.4" -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.1", features = ["derive"], optional = true } nohash-hasher = { version = "0.2.0" } stacker = "0.1.15" thiserror = "1.0.58" @@ -33,7 +34,8 @@ thiserror = "1.0.58" ##--COMPILER-CUTOFF--## [features] -default = ["_full_cli"] +default = ["cli", "_full_cli"] +cli = ["dep:clap"] trace = [] _full_cli = [] _fuzz = [] diff --git a/src/main.rs b/src/main.rs index 5746f89b..90939e7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use hvmc::{ host::Host, run::{DynNet, Mode, Trg}, stdlib::create_host, + transform::{TransformOpts, TransformPass, TransformPasses}, *, }; @@ -25,28 +26,28 @@ fn main() { if cfg!(feature = "_full_cli") { let cli = FullCli::parse(); match cli.mode { - CliMode::Compile { file, transform_opts, output } => { + CliMode::Compile { file, transform_args, output } => { let output = output.as_deref().or_else(|| file.strip_suffix(".hvmc")).unwrap_or_else(|| { eprintln!("file missing `.hvmc` extension; explicitly specify an output path with `--output`."); process::exit(1); }); - let host = create_host(&load_book(&[file.clone()], &transform_opts)); + let host = create_host(&load_book(&[file.clone()], &transform_args)); compile_executable(output, host).unwrap(); } - CliMode::Run { run_opts, mut transform_opts, file, args } => { + CliMode::Run { run_opts, mut transform_args, file, args } => { // Don't pre-reduce or prune the entry point - transform_opts.pre_reduce_skip.push(args.entry_point.clone()); - transform_opts.prune_entrypoints.push(args.entry_point.clone()); - let host = create_host(&load_book(&[file], &transform_opts)); + transform_args.transform_opts.pre_reduce_skip.push(args.entry_point.clone()); + transform_args.transform_opts.prune_entrypoints.push(args.entry_point.clone()); + let host = create_host(&load_book(&[file], &transform_args)); run(host, run_opts, args); } - CliMode::Reduce { run_opts, transform_opts, files, exprs } => { - let host = create_host(&load_book(&files, &transform_opts)); + CliMode::Reduce { run_opts, transform_args, files, exprs } => { + let host = create_host(&load_book(&files, &transform_args)); let exprs: Vec<_> = exprs.iter().map(|x| Net::from_str(x).unwrap()).collect(); reduce_exprs(host, &exprs, &run_opts); } - CliMode::Transform { transform_opts, files } => { - let book = load_book(&files, &transform_opts); + CliMode::Transform { transform_args, files } => { + let book = load_book(&files, &transform_args); println!("{}", book); } } @@ -100,7 +101,7 @@ enum CliMode { /// Output path; defaults to the input file with `.hvmc` stripped. output: Option, #[command(flatten)] - transform_opts: TransformOpts, + transform_args: TransformArgs, }, /// Run a program, optionally passing a list of arguments to it. Run { @@ -111,7 +112,7 @@ enum CliMode { #[command(flatten)] run_opts: RuntimeOpts, #[command(flatten)] - transform_opts: TransformOpts, + transform_args: TransformArgs, }, /// Reduce hvm-core expressions to their normal form. /// @@ -135,7 +136,7 @@ enum CliMode { #[command(flatten)] run_opts: RuntimeOpts, #[command(flatten)] - transform_opts: TransformOpts, + transform_args: TransformArgs, }, /// Transform a hvm-core program using one of the optimization passes. Transform { @@ -145,36 +146,18 @@ enum CliMode { #[arg(required = true)] files: Vec, #[command(flatten)] - transform_opts: TransformOpts, + transform_args: TransformArgs, }, } #[derive(Args, Clone, Debug)] -struct TransformOpts { - #[arg(short = 'O', value_delimiter = ' ', action = clap::ArgAction::Append)] +struct TransformArgs { /// Enables or disables transformation passes. + #[arg(short = 'O', value_delimiter = ' ', action = clap::ArgAction::Append)] transform_passes: Vec, - #[arg(long = "pre-reduce-skip", value_delimiter = ' ', action = clap::ArgAction::Append)] - /// Names of the definitions that should not get pre-reduced. - /// - /// For programs that don't take arguments - /// and don't have side effects this is usually the entry point of the - /// program (otherwise, the whole program will get reduced to normal form). - pre_reduce_skip: Vec, - #[arg(long = "pre-reduce-memory", value_parser = parse_abbrev_number::)] - /// How much memory to allocate when pre-reducing. - /// - /// Supports abbreviations such as '4G' or '400M'. - pre_reduce_memory: Option, - #[arg(long = "pre-reduce-rewrites", default_value = "100M", value_parser = parse_abbrev_number::)] - /// Maximum amount of rewrites to do when pre-reducing. - /// - /// Supports abbreviations such as '4G' or '400M'. - pre_reduce_rewrites: u64, - /// Names of the definitions that should not get pruned. - #[arg(long = "prune-entrypoints", default_value = "main")] - prune_entrypoints: Vec, + #[command(flatten)] + transform_opts: TransformOpts, } #[derive(Args, Clone, Debug)] @@ -192,7 +175,7 @@ struct RuntimeOpts { /// by a walk from the root of the net. This leads to a dramatic slowdown, /// but allows running programs that would expand indefinitely otherwise. lazy_mode: bool, - #[arg(short = 'm', long = "memory", value_parser = parse_abbrev_number::)] + #[arg(short = 'm', long = "memory", value_parser = util::parse_abbrev_number::)] /// How much memory to allocate on startup. /// /// Supports abbreviations such as '4G' or '400M'. @@ -213,73 +196,6 @@ struct RunArgs { args: Vec, } -macro_rules! transform_passes { - ($($pass:ident: $name:literal $(| $alias:literal)*),* $(,)?) => { - #[derive(Clone, Debug)] - #[allow(non_camel_case_types)] - pub enum TransformPass { - all(bool), - $($pass(bool),)* - } - - #[derive(Default)] - struct TransformPasses { - $($pass: bool),* - } - - impl TransformPasses { - fn set_all(&mut self) { - $(self.$pass = true;)* - } - } - - impl clap::ValueEnum for TransformPass { - fn value_variants<'a>() -> &'a [Self] { - &[ - Self::all(true), Self::all(false), - $(Self::$pass(true), Self::$pass(false),)* - ] - } - - fn to_possible_value(&self) -> Option { - use TransformPass::*; - Some(match self { - all(true) => clap::builder::PossibleValue::new("all"), - all(false) => clap::builder::PossibleValue::new("no-all"), - $( - $pass(true) => clap::builder::PossibleValue::new($name)$(.alias($alias))*, - $pass(false) => clap::builder::PossibleValue::new(concat!("no-", $name))$(.alias(concat!("no-", $alias)))*, - )* - }) - } - } - - impl TransformPass { - fn passes_from_cli(args: &Vec) -> TransformPasses { - use TransformPass::*; - let mut opts = TransformPasses::default(); - for arg in args { - match arg { - all(true) => opts.set_all(), - all(false) => opts = TransformPasses::default(), - $(&$pass(b) => opts.$pass = b,)* - } - } - opts - } - } - }; -} - -transform_passes! { - pre_reduce: "pre-reduce" | "pre", - coalesce_ctrs: "coalesce-ctrs" | "coalesce", - encode_adts: "encode-adts" | "adts", - eta_reduce: "eta-reduce" | "eta", - inline: "inline", - prune: "prune", -} - fn run(host: Arc>, opts: RuntimeOpts, args: RunArgs) { let mut net = Net { root: Tree::Ref { nam: args.entry_point }, redexes: vec![] }; for arg in args.args { @@ -290,29 +206,8 @@ fn run(host: Arc>, opts: RuntimeOpts, args: RunArgs) { reduce_exprs(host, &[net], &opts); } -/// Turn a string representation of a number, such as '1G' or '400K', into a -/// number. -/// -/// This return a [`u64`] instead of [`usize`] to ensure that parsing CLI args -/// doesn't fail on 32-bit systems. We want it to fail later on, when attempting -/// to run the program. -fn parse_abbrev_number>(arg: &str) -> Result -where - >::Error: core::fmt::Debug, -{ - let (base, scale) = match arg.to_lowercase().chars().last() { - None => return Err("Mem size argument is empty".to_string()), - Some('k') => (&arg[0 .. arg.len() - 1], 1u64 << 10), - Some('m') => (&arg[0 .. arg.len() - 1], 1u64 << 20), - Some('g') => (&arg[0 .. arg.len() - 1], 1u64 << 30), - Some('t') => (&arg[0 .. arg.len() - 1], 1u64 << 40), - Some(_) => (arg, 1), - }; - let base = base.parse::().map_err(|e| e.to_string())?; - Ok((base * scale).try_into().map_err(|e| format!("{:?}", e))?) -} -fn load_book(files: &[String], transform_opts: &TransformOpts) -> Book { +fn load_book(files: &[String], transform_args: &TransformArgs) -> Book { let mut book = files .iter() .map(|name| { @@ -329,58 +224,10 @@ fn load_book(files: &[String], transform_opts: &TransformOpts) -> Book { acc.nets.extend(i.nets); acc }); - let transform_passes = TransformPass::passes_from_cli(&transform_opts.transform_passes); - if transform_passes.pre_reduce { - if transform_passes.eta_reduce { - for (_, def) in &mut book.nets { - def.eta_reduce(); - } - } - book.pre_reduce( - &|x| transform_opts.pre_reduce_skip.iter().any(|y| x == y), - transform_opts.pre_reduce_memory, - transform_opts.pre_reduce_rewrites, - ); - } - for (_, def) in &mut book.nets { - if transform_passes.eta_reduce { - def.eta_reduce(); - } - for tree in def.trees_mut() { - if transform_passes.coalesce_ctrs { - tree.coalesce_constructors(); - } - if transform_passes.encode_adts { - tree.encode_scott_adts(); - } - } - } - if transform_passes.inline { - loop { - let inline_changed = book.inline().unwrap(); - if inline_changed.is_empty() { - break; - } - if !(transform_passes.eta_reduce || transform_passes.encode_adts) { - break; - } - for name in inline_changed { - let def = book.get_mut(&name).unwrap(); - if transform_passes.eta_reduce { - def.eta_reduce(); - } - if transform_passes.encode_adts { - for tree in def.trees_mut() { - tree.encode_scott_adts(); - } - } - } - } - } - if transform_passes.prune { - book.prune(&transform_opts.prune_entrypoints); - } + let transform_passes = TransformPasses::from(&transform_args.transform_passes[..]); + book.transform(transform_passes, &transform_args.transform_opts).unwrap(); + book } @@ -434,7 +281,8 @@ fn compile_executable(target: &str, host: Arc>) -> Result<(), fs::remove_dir_all(outdir)?; } let cargo_toml = include_str!("../Cargo.toml"); - let cargo_toml = cargo_toml.split("##--COMPILER-CUTOFF--##").next().unwrap(); + let mut cargo_toml = cargo_toml.split_once("##--COMPILER-CUTOFF--##").unwrap().0.to_owned(); + cargo_toml.push_str("[features]\ndefault = ['cli']\ncli = ['dep:clap']"); macro_rules! include_files { ($([$($prefix:ident)*])? $mod:ident {$($sub:tt)*} $($rest:tt)*) => { @@ -499,6 +347,7 @@ fn compile_executable(target: &str, host: Arc>) -> Result<(), create_var deref maybe_grow + parse_abbrev_number stats } } diff --git a/src/transform.rs b/src/transform.rs index cecde3bd..023aed19 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,5 +1,7 @@ use thiserror::Error; +use crate::{ast::Book, util}; + pub mod coalesce_ctrs; pub mod encode_adts; pub mod eta_reduce; @@ -13,3 +15,166 @@ pub enum TransformError { #[error("infinite reference cycle in `@{0}`")] InfiniteRefCycle(String), } + +impl Book { + pub fn transform(&mut self, passes: TransformPasses, opts: &TransformOpts) -> Result<(), TransformError> { + if passes.prune { + self.prune(&opts.prune_entrypoints); + } + if passes.pre_reduce { + if passes.eta_reduce { + for (_, def) in &mut self.nets { + def.eta_reduce(); + } + } + self.pre_reduce( + &|x| opts.pre_reduce_skip.iter().any(|y| x == y), + opts.pre_reduce_memory, + opts.pre_reduce_rewrites, + ); + } + for (_, def) in &mut self.nets { + if passes.eta_reduce { + def.eta_reduce(); + } + for tree in def.trees_mut() { + if passes.coalesce_ctrs { + tree.coalesce_constructors(); + } + if passes.encode_adts { + tree.encode_scott_adts(); + } + } + } + if passes.inline { + loop { + let inline_changed = self.inline()?; + if inline_changed.is_empty() { + break; + } + if !(passes.eta_reduce || passes.encode_adts) { + break; + } + for name in inline_changed { + let def = self.get_mut(&name).unwrap(); + if passes.eta_reduce { + def.eta_reduce(); + } + if passes.encode_adts { + for tree in def.trees_mut() { + tree.encode_scott_adts(); + } + } + } + } + } + if passes.prune { + self.prune(&opts.prune_entrypoints); + } + Ok(()) + } +} + +#[derive(Clone, Debug)] +#[cfg_attr(feature = "cli", derive(clap::Args))] +#[non_exhaustive] +pub struct TransformOpts { + /// Names of the definitions that should not get pre-reduced. + /// + /// For programs that don't take arguments and don't have side effects this is + /// usually the entry point of the program (otherwise, the whole program will + /// get reduced to normal form). + #[cfg_attr(feature = "cli", arg(long = "pre-reduce-skip", value_delimiter = ' ', action = clap::ArgAction::Append))] + pub pre_reduce_skip: Vec, + + /// 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::))] + 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::))] + pub pre_reduce_rewrites: u64, + + /// Names of the definitions that should not get pruned. + #[cfg_attr(feature = "cli", arg(long = "prune-entrypoints", default_value = "main"))] + pub prune_entrypoints: Vec, +} + +impl TransformOpts { + pub fn add_entrypoint(&mut self, entrypoint: &str) { + self.pre_reduce_skip.push(entrypoint.to_owned()); + self.prune_entrypoints.push(entrypoint.to_owned()); + } +} + +macro_rules! transform_passes { + ($($pass:ident: $name:literal $(| $alias:literal)*),* $(,)?) => { + #[derive(Debug, Default, Clone, Copy)] + #[non_exhaustive] + pub struct TransformPasses { + $(pub $pass: bool),* + } + + impl TransformPasses { + pub const NONE: Self = Self { $($pass: false),* }; + pub const ALL: Self = Self { $($pass: true),* }; + } + + #[derive(Debug, Clone, Copy)] + #[allow(non_camel_case_types)] + pub enum TransformPass { + all(bool), + $($pass(bool),)* + } + + #[cfg(feature = "cli")] + impl clap::ValueEnum for TransformPass { + fn value_variants<'a>() -> &'a [Self] { + &[ + Self::all(true), Self::all(false), + $(Self::$pass(true), Self::$pass(false),)* + ] + } + + fn to_possible_value(&self) -> Option { + use TransformPass::*; + Some(match self { + all(true) => clap::builder::PossibleValue::new("all"), + all(false) => clap::builder::PossibleValue::new("no-all"), + $( + $pass(true) => clap::builder::PossibleValue::new($name)$(.alias($alias))*, + $pass(false) => clap::builder::PossibleValue::new(concat!("no-", $name))$(.alias(concat!("no-", $alias)))*, + )* + }) + } + } + + impl From<&[TransformPass]> for TransformPasses { + fn from(args: &[TransformPass]) -> TransformPasses { + use TransformPass::*; + let mut opts = TransformPasses::NONE; + for arg in args { + match arg { + all(true) => opts = TransformPasses::ALL, + all(false) => opts = TransformPasses::NONE, + $(&$pass(b) => opts.$pass = b,)* + } + } + opts + } + } + }; +} + +transform_passes! { + pre_reduce: "pre-reduce" | "pre", + coalesce_ctrs: "coalesce-ctrs" | "coalesce", + encode_adts: "encode-adts" | "adts", + eta_reduce: "eta-reduce" | "eta", + inline: "inline", + prune: "prune", +} diff --git a/src/util.rs b/src/util.rs index 7090843d..a4770622 100644 --- a/src/util.rs +++ b/src/util.rs @@ -4,10 +4,12 @@ mod bi_enum; mod create_var; mod deref; mod maybe_grow; +mod parse_abbrev_number; mod stats; pub(crate) use bi_enum::*; pub(crate) use create_var::*; pub(crate) use deref::*; pub(crate) use maybe_grow::*; +pub use parse_abbrev_number::*; pub use stats::*; diff --git a/src/util/parse_abbrev_number.rs b/src/util/parse_abbrev_number.rs new file mode 100644 index 00000000..ede54401 --- /dev/null +++ b/src/util/parse_abbrev_number.rs @@ -0,0 +1,17 @@ +/// 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, +{ + let (base, scale) = match arg.to_lowercase().chars().last() { + None => return Err("Mem size argument is empty".to_string()), + Some('k') => (&arg[0 .. arg.len() - 1], 1u64 << 10), + Some('m') => (&arg[0 .. arg.len() - 1], 1u64 << 20), + Some('g') => (&arg[0 .. arg.len() - 1], 1u64 << 30), + Some('t') => (&arg[0 .. arg.len() - 1], 1u64 << 40), + Some(_) => (arg, 1), + }; + let base = base.parse::().map_err(|e| e.to_string())?; + Ok((base * scale).try_into().map_err(|e| format!("{:?}", e))?) +} From 7626300127be82bf4c55e2dfe3a915e4a6ca21e7 Mon Sep 17 00:00:00 2001 From: T6 Date: Wed, 10 Apr 2024 16:26:46 -0400 Subject: [PATCH 4/5] add `no_std` support (#123) --- .github/workflows/checks.yml | 1 + Cargo.lock | 1 + Cargo.toml | 6 ++++-- src/ast.rs | 14 +++++++++----- src/compile.rs | 10 ++++++---- src/fuzz.rs | 11 +++++++++-- src/host.rs | 19 +++++++++++-------- src/host/calc_labels.rs | 18 +++++++++++++----- src/host/encode.rs | 4 +++- src/host/readback.rs | 4 +++- src/lib.rs | 5 +++++ src/main.rs | 12 +++++++----- src/ops.rs | 9 +++++---- src/prelude.rs | 20 ++++++++++++++++++++ src/run.rs | 17 ++++++++--------- src/run/allocator.rs | 4 ++-- src/run/net.rs | 12 ++++++------ src/run/parallel.rs | 7 +++++++ src/stdlib.rs | 27 ++++++++++++++------------- src/trace.rs | 22 ++++++++++++---------- src/transform.rs | 13 +++++++------ src/transform/coalesce_ctrs.rs | 4 +++- src/transform/encode_adts.rs | 4 +++- src/transform/eta_reduce.rs | 5 +++-- src/transform/inline.rs | 15 ++++++--------- src/transform/pre_reduce.rs | 15 +++++++-------- src/transform/prune.rs | 4 ++-- src/util/apply_tree.rs | 5 +++-- src/util/bi_enum.rs | 10 ++++++---- src/util/create_var.rs | 2 ++ src/util/deref.rs | 4 ++-- src/util/parse_abbrev_number.rs | 4 +++- src/util/stats.rs | 6 ++++-- tests/lists.rs | 2 ++ tests/loaders/mod.rs | 4 ++-- tests/tests.rs | 9 ++++++--- tests/transform.rs | 2 ++ 37 files changed, 209 insertions(+), 122 deletions(-) create mode 100644 src/prelude.rs 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; From 51a5d2336f28627e34c135c85859b764ce8ce993 Mon Sep 17 00:00:00 2001 From: T6 Date: Thu, 11 Apr 2024 16:32:33 -0400 Subject: [PATCH 5/5] use clippy (#124) --- .github/workflows/checks.yml | 17 +++++++++++++++++ src/ast.rs | 23 ++++++++++------------- src/compile.rs | 4 ++-- src/fuzz.rs | 5 +++-- src/host.rs | 2 +- src/lib.rs | 14 +++++++++++++- src/prelude.rs | 2 +- src/run/allocator.rs | 7 +++++-- src/run/def.rs | 12 ++++++------ src/run/dyn_net.rs | 24 +++++++++++++++++++++--- src/run/instruction.rs | 10 +++------- src/run/linker.rs | 8 ++++---- src/run/net.rs | 9 +-------- src/run/node.rs | 8 ++------ src/run/parallel.rs | 12 ++++++------ src/stdlib.rs | 21 ++++++++------------- src/trace.rs | 14 ++++++++------ src/transform.rs | 4 ++-- src/transform/coalesce_ctrs.rs | 2 +- src/transform/eta_reduce.rs | 3 +-- src/transform/pre_reduce.rs | 4 ++-- src/util/parse_abbrev_number.rs | 2 +- src/util/stats.rs | 6 +++--- tests/cli.rs | 23 +++++++++++------------ tests/fuzz.rs | 20 ++++++++++---------- tests/lists.rs | 4 ++-- tests/tests.rs | 2 +- 27 files changed, 145 insertions(+), 117 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index bd8effaa..9f577fb2 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -25,6 +25,23 @@ jobs: - 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 + clippy: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3 + - uses: dsherret/rust-toolchain-file@v1 + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.lock') }} + - run: RUSTFLAGS="-D warnings" cargo clippy --all-targets + - run: RUSTFLAGS="-D warnings" cargo clippy --all-targets --features trace + - run: RUSTFLAGS="-D warnings" cargo clippy --all-targets --features _fuzz + - run: RUSTFLAGS="-D warnings" cargo clippy --all-targets --no-default-features test: runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/src/ast.rs b/src/ast.rs index 2f45e723..52efcf4e 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -149,16 +149,16 @@ pub const MAX_ADT_FIELDS: usize = MAX_ARITY - 1; impl Net { pub fn trees(&self) -> impl Iterator { - iter::once(&self.root).chain(self.redexes.iter().map(|(x, y)| [x, y]).flatten()) + iter::once(&self.root).chain(self.redexes.iter().flat_map(|(x, y)| [x, y])) } pub fn trees_mut(&mut self) -> impl Iterator { - 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().flat_map(|(x, y)| [x, y])) } } impl Tree { #[inline(always)] - pub fn children(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { + pub fn children(&self) -> impl ExactSizeIterator + DoubleEndedIterator { ArrayVec::<_, MAX_ARITY>::into_iter(match self { Tree::Era | Tree::Num { .. } | Tree::Ref { .. } | Tree::Var { .. } => array_vec::from_array([]), Tree::Ctr { ports, .. } => array_vec::from_iter(ports), @@ -169,7 +169,7 @@ impl Tree { } #[inline(always)] - pub fn children_mut(&mut self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { + pub fn children_mut(&mut self) -> impl ExactSizeIterator + DoubleEndedIterator { ArrayVec::<_, MAX_ARITY>::into_iter(match self { Tree::Era | Tree::Num { .. } | Tree::Ref { .. } | Tree::Var { .. } => array_vec::from_array([]), Tree::Ctr { ports, .. } => array_vec::from_iter(ports), @@ -470,17 +470,14 @@ impl Clone for Tree { fn clone(&self) -> Tree { maybe_grow(|| match self { Tree::Era => Tree::Era, - Tree::Num { val } => Tree::Num { val: val.clone() }, + Tree::Num { val } => Tree::Num { val: *val }, Tree::Ref { nam } => Tree::Ref { nam: nam.clone() }, - Tree::Ctr { lab, ports } => Tree::Ctr { lab: lab.clone(), ports: ports.clone() }, - Tree::Op { op, rhs, out } => Tree::Op { op: op.clone(), rhs: rhs.clone(), out: out.clone() }, + Tree::Ctr { lab, ports } => Tree::Ctr { lab: *lab, ports: ports.clone() }, + Tree::Op { op, rhs, out } => Tree::Op { op: *op, rhs: rhs.clone(), out: out.clone() }, Tree::Mat { zero, succ, out } => Tree::Mat { zero: zero.clone(), succ: succ.clone(), out: out.clone() }, - Tree::Adt { lab, variant_index, variant_count, fields } => Tree::Adt { - lab: lab.clone(), - variant_index: variant_index.clone(), - variant_count: variant_count.clone(), - fields: fields.clone(), - }, + Tree::Adt { lab, variant_index, variant_count, fields } => { + Tree::Adt { lab: *lab, variant_index: *variant_index, variant_count: *variant_count, fields: fields.clone() } + } Tree::Var { nam } => Tree::Var { nam: nam.clone() }, }) } diff --git a/src/compile.rs b/src/compile.rs index bb83d24c..0ed92fc9 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -7,8 +7,8 @@ use crate::{ run::{Instruction, InterpretedDef, LabSet, Port, Tag}, stdlib::HostedDef, }; -use core::hash::Hasher; -use std::{fmt::Write, hash::DefaultHasher}; +use core::{fmt::Write, hash::Hasher}; +use std::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 ec3c519a..a945c39b 100644 --- a/src/fuzz.rs +++ b/src/fuzz.rs @@ -72,6 +72,7 @@ use crate::prelude::*; +use alloc::sync::Arc; use core::{ any::Any, cell::{OnceCell, RefCell}, @@ -81,7 +82,7 @@ use core::{ sync::atomic, }; use std::{ - sync::{Arc, Condvar, Mutex}, + sync::{Condvar, Mutex}, thread::{self, Scope, ThreadId}, thread_local, }; @@ -460,7 +461,7 @@ impl<'s, 'p: 's, 'e: 's> FuzzScope<'s, 'p, 'e> { } }); while !ready.load(atomic::Ordering::Relaxed) { - std::hint::spin_loop() + hint::spin_loop() } } } diff --git a/src/host.rs b/src/host.rs index 479d3397..7ea67829 100644 --- a/src/host.rs +++ b/src/host.rs @@ -77,7 +77,7 @@ impl Host { for (name, labs) in calculate_label_sets(book, |nam| match self.defs.get(nam) { Some(x) => x.labs.clone(), None => { - self.insert_def(&nam, default_def(nam)); + self.insert_def(nam, default_def(nam)); self.defs[nam].labs.clone() } }) diff --git a/src/lib.rs b/src/lib.rs index 6fc67f4f..f1213e9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,19 @@ #![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)] +#![allow( + non_snake_case, + incomplete_features, + clippy::field_reassign_with_default, + clippy::missing_safety_doc, + clippy::new_ret_no_self +)] +#![warn( + clippy::alloc_instead_of_core, + clippy::std_instead_of_core, + clippy::std_instead_of_alloc, + clippy::absolute_paths +)] extern crate alloc; diff --git a/src/prelude.rs b/src/prelude.rs index 43511de3..e6f23d19 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,7 +6,7 @@ pub use alloc::{ vec, vec::Vec, }; -pub use core::{fmt, iter, mem, ptr}; +pub use core::{fmt, hint, iter, mem, ptr}; #[cfg(feature = "std")] pub use std::collections::{hash_map::Entry, HashMap as Map, HashSet as Set}; diff --git a/src/run/allocator.rs b/src/run/allocator.rs index ab6867f4..525aea02 100644 --- a/src/run/allocator.rs +++ b/src/run/allocator.rs @@ -1,5 +1,8 @@ use super::*; +// Really, rust? +use alloc::alloc::alloc; + /// The memory behind a two-word allocation. /// /// This must be aligned to 16 bytes so that the left word's address always ends @@ -41,7 +44,7 @@ impl Heap { return None; } unsafe { - let ptr = alloc::alloc::alloc(Layout::array::(nodes).unwrap()) as *mut Node; + let ptr = alloc(Layout::array::(nodes).unwrap()) as *mut Node; if ptr.is_null() { return None; } @@ -96,7 +99,7 @@ impl<'h> Allocator<'h> { pub fn alloc(&mut self) -> Addr { trace!(self.tracer, self.head); let addr = if self.head != Addr::NULL { - let addr = self.head.clone(); + let addr = self.head; let next = Addr(self.head.val().load(Relaxed) as usize); trace!(self.tracer, next); self.head = next; diff --git a/src/run/def.rs b/src/run/def.rs index a72e508d..7ee9b801 100644 --- a/src/run/def.rs +++ b/src/run/def.rs @@ -145,9 +145,9 @@ impl Def { } #[inline(always)] pub unsafe fn call(slf: *const Def, net: &mut Net, port: Port) { - match net.match_laziness_mut() { - Ok(net) => ((*slf).call_lazy)(slf as *const _, net, port), - Err(net) => ((*slf).call_strict)(slf as *const _, net, port), + match net.as_dyn_mut() { + DynNetMut::Strict(net) => ((*slf).call_strict)(slf as *const _, net, port), + DynNetMut::Lazy(net) => ((*slf).call_lazy)(slf as *const _, net, port), } } } @@ -171,9 +171,9 @@ impl, Port) + Send + Sync + 'static, G: Fn(&mut Net for (F, G) { unsafe fn call(slf: *const Def, net: &mut Net, port: Port) { - match net.match_laziness_mut() { - Ok(net) => ((*slf).data.1)(net, port), - Err(net) => ((*slf).data.0)(net, port), + match net.as_dyn_mut() { + DynNetMut::Strict(net) => ((*slf).data.0)(net, port), + DynNetMut::Lazy(net) => ((*slf).data.1)(net, port), } } } diff --git a/src/run/dyn_net.rs b/src/run/dyn_net.rs index 37a58fd8..ec80a0b5 100644 --- a/src/run/dyn_net.rs +++ b/src/run/dyn_net.rs @@ -1,5 +1,7 @@ use super::{Heap, Lazy, Mode, Net, Strict}; +use crate::prelude::*; + /// A [`Net`] whose mode is determined dynamically, at runtime. /// /// Use [`dispatch_dyn_net!`] to wrap operations on the inner net. @@ -24,12 +26,28 @@ impl<'h> DynNet<'h> { impl<'r, 'h, M: Mode> From<&'r mut Net<'h, M>> for DynNetMut<'r, 'h> { fn from(value: &'r mut Net<'h, M>) -> Self { - match value.match_laziness_mut() { - Ok(net) => DynNetMut::Lazy(net), - Err(net) => DynNetMut::Strict(net), + value.as_dyn_mut() + } +} + +impl<'h, M: Mode> Net<'h, M> { + pub fn as_dyn_mut(&mut self) -> DynNetMut<'_, 'h> { + if M::LAZY { + DynNetMut::Lazy(unsafe { mem::transmute(self) }) + } else { + DynNetMut::Strict(unsafe { mem::transmute(self) }) + } + } + + pub fn into_dyn(self) -> DynNet<'h> { + if M::LAZY { + DynNet::Lazy(unsafe { mem::transmute(self) }) + } else { + DynNet::Strict(unsafe { mem::transmute(self) }) } } } + #[macro_export] macro_rules! dispatch_dyn_net { ($pat:pat = $expr:expr => $body:expr) => { diff --git a/src/run/instruction.rs b/src/run/instruction.rs index 4390eb11..c9794d97 100644 --- a/src/run/instruction.rs +++ b/src/run/instruction.rs @@ -112,6 +112,7 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub(crate) fn do_ctr(&mut self, lab: Lab, trg: Trg) -> (Trg, Trg) { let port = trg.target(); + #[allow(clippy::overly_complex_bool_expr)] if !M::LAZY && port.tag() == Ctr && port.lab() == lab { trace!(self.tracer, "fast"); self.free_trg(trg); @@ -119,7 +120,7 @@ impl<'a, M: Mode> Net<'a, M> { self.rwts.anni += 1; (Trg::wire(node.p1), Trg::wire(node.p2)) // TODO: fast copy? - } else if false && !M::LAZY && port.tag() == Num || port.tag() == Ref && lab >= port.lab() { + } else if false && !M::LAZY && (port.tag() == Num || port.tag() == Ref && lab >= port.lab()) { self.rwts.comm += 1; self.free_trg(trg); (Trg::port(port.clone()), Trg::port(port)) @@ -203,12 +204,7 @@ impl<'a, M: Mode> Net<'a, M> { pub(crate) fn do_wires(&mut self) -> (Trg, Trg, Trg, Trg) { let a = self.alloc(); let b = a.other_half(); - ( - Trg::port(Port::new_var(a.clone())), - Trg::wire(Wire::new(a)), - Trg::port(Port::new_var(b.clone())), - Trg::wire(Wire::new(b)), - ) + (Trg::port(Port::new_var(a)), Trg::wire(Wire::new(a)), Trg::port(Port::new_var(b)), Trg::wire(Wire::new(b))) } /// `trg ~ ?<(x (y z)) out>` diff --git a/src/run/linker.rs b/src/run/linker.rs index 82b1091a..a92da3f3 100644 --- a/src/run/linker.rs +++ b/src/run/linker.rs @@ -111,10 +111,8 @@ impl<'h, M: Mode> Linker<'h, M> { trace!(self, a_port, b_port); if a_port.is(Tag::Var) { a_port.wire().set_target(b_port); - } else { - if M::LAZY { - self.set_header(a_port, b_port); - } + } else if M::LAZY { + self.set_header(a_port, b_port); } } @@ -284,11 +282,13 @@ impl Trg { } #[inline(always)] + #[allow(clippy::wrong_self_convention)] pub(super) fn as_wire(self) -> Wire { Wire(self.0.0 as _) } #[inline(always)] + #[allow(clippy::wrong_self_convention)] pub(super) fn as_port(self) -> Port { self.0 } diff --git a/src/run/net.rs b/src/run/net.rs index 89a1a1e6..b5934aaa 100644 --- a/src/run/net.rs +++ b/src/run/net.rs @@ -29,13 +29,6 @@ impl<'h, M: Mode> Net<'h, M> { pub fn boot(&mut self, def: &Def) { self.call(Port::new_ref(def), self.root.as_var()); } - - pub fn match_laziness_mut(&mut self) -> Result<&mut Net<'h, Lazy>, &mut Net<'h, Strict>> { - 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 { mem::transmute(self) }) } else { Err(unsafe { mem::transmute(self) }) } - } } impl<'a, M: Mode> Net<'a, M> { @@ -99,7 +92,7 @@ impl<'a, M: Mode> Net<'a, M> { prev = main.this.clone(); } - return self.get_target_full(prev); + self.get_target_full(prev) } pub fn normal_from(&mut self, root: Wire) { diff --git a/src/run/node.rs b/src/run/node.rs index fb0116d2..7fdec7e3 100644 --- a/src/run/node.rs +++ b/src/run/node.rs @@ -35,11 +35,7 @@ impl<'a, M: Mode> Net<'a, M> { #[inline(always)] pub fn create_node(&mut self, tag: Tag, lab: Lab) -> CreatedNode { let addr = self.alloc(); - CreatedNode { - p0: Port::new(tag, lab, addr.clone()), - p1: Port::new_var(addr.clone()), - p2: Port::new_var(addr.other_half()), - } + CreatedNode { p0: Port::new(tag, lab, addr), p1: Port::new_var(addr), p2: Port::new_var(addr.other_half()) } } /// Creates a wire an aux port pair. @@ -47,7 +43,7 @@ impl<'a, M: Mode> Net<'a, M> { pub fn create_wire(&mut self) -> (Wire, Port) { let addr = self.alloc(); self.half_free(addr.other_half()); - (Wire::new(addr.clone()), Port::new_var(addr)) + (Wire::new(addr), Port::new_var(addr)) } /// Creates a wire pointing to a given port; sometimes necessary to avoid diff --git a/src/run/parallel.rs b/src/run/parallel.rs index b1369ff2..5c7babb8 100644 --- a/src/run/parallel.rs +++ b/src/run/parallel.rs @@ -18,7 +18,7 @@ impl<'h, M: Mode> Net<'h, M> { (0 .. tids).map(move |tid| { let heap_size = (heap.0.len() / tids) & !63; // round down to needed alignment let heap_start = heap_size * tid; - let area = unsafe { std::mem::transmute(&heap.0[heap_start .. heap_start + heap_size]) }; + let area = unsafe { mem::transmute(&heap.0[heap_start .. heap_start + heap_size]) }; let mut net = Net::new_with_root(area, root.clone()); net.next = next.saturating_sub(heap_start); net.head = if tid == 0 { net.head } else { Addr::NULL }; @@ -54,7 +54,7 @@ impl<'h, M: Mode> Net<'h, M> { } // Initialize global objects - let cores = std::thread::available_parallelism().unwrap().get() as usize; + let cores = thread::available_parallelism().unwrap().get(); let tlog2 = cores.ilog2() as usize; let tids = 1 << tlog2; let delta = AtomicRewrites::default(); // delta rewrite counter @@ -64,7 +64,7 @@ impl<'h, M: Mode> Net<'h, M> { let barry = Arc::new(Barrier::new(tids)); // global barrier // Perform parallel reductions - std::thread::scope(|s| { + thread::scope(|s| { for net in self.fork(tids) { let mut ctx = ThreadContext { tid: net.tid, @@ -133,11 +133,11 @@ impl<'h, M: Mode> Net<'h, M> { let b_len = ctx.rlens[b_tid].load(Relaxed); let send = if a_len > b_len { (a_len - b_len) / 2 } else { 0 }; let recv = if b_len > a_len { (b_len - a_len) / 2 } else { 0 }; - let send = std::cmp::min(send, SHARE_LIMIT); - let recv = std::cmp::min(recv, SHARE_LIMIT); + let send = usize::min(send, SHARE_LIMIT); + let recv = usize::min(recv, SHARE_LIMIT); for i in 0 .. send { let init = a_len - send * 2; - let rdx0 = ctx.net.redexes.slow[init + i * 2 + 0].clone(); + let rdx0 = ctx.net.redexes.slow[init + i * 2].clone(); let rdx1 = ctx.net.redexes.slow[init + i * 2 + 1].clone(); //let init = 0; //let ref0 = ctx.net.redexes.get_unchecked_mut(init + i * 2 + 0); diff --git a/src/stdlib.rs b/src/stdlib.rs index 4c861fb4..f271a20f 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -60,6 +60,7 @@ impl AsHostedDef for LogDef { /// Create a `Host` from a `Book`, including `hvm-core`'s built-in definitions #[cfg(feature = "std")] +#[allow(clippy::absolute_paths)] pub fn create_host(book: &crate::ast::Book) -> Arc> { let host = Arc::new(Mutex::new(Host::default())); host.lock().insert_def("HVM.log", unsafe { @@ -70,7 +71,7 @@ pub fn create_host(book: &crate::ast::Book) -> Arc> { }) }); host.lock().insert_def("HVM.black_box", DefRef::Static(unsafe { &*IDENTITY })); - host.lock().insert_book(&book); + host.lock().insert_book(book); host } @@ -84,11 +85,8 @@ impl BoxDef { /// SAFETY: if port is a ref, it must be a valid pointer. pub unsafe fn try_downcast_box(port: Port) -> Option>> { if port.is(Tag::Ref) { - if let Some(port) = unsafe { Def::downcast_ptr::(port.addr().0 as *const _) } { - Some(unsafe { Box::from_raw(port as *mut Def) }) - } else { - None - } + unsafe { Def::downcast_ptr::(port.addr().0 as *const _) } + .map(|port| unsafe { Box::from_raw(port as *mut Def) }) } else { None } @@ -121,11 +119,8 @@ impl ArcDef { /// SAFETY: if port is a ref, it must be a valid pointer. pub unsafe fn try_downcast_arc(port: Port) -> Option>> { if port.is(Tag::Ref) && port != Port::ERA { - if let Some(port) = unsafe { Def::downcast_ptr::(port.addr().0 as *const _) } { - Some(unsafe { Arc::from_raw(port as *mut Def) }) - } else { - None - } + unsafe { Def::downcast_ptr::(port.addr().0 as *const _) } + .map(|port| unsafe { Arc::from_raw(port as *mut Def) }) } else { None } @@ -182,7 +177,7 @@ pub struct ReadbackDef { } impl ReadbackDef { - fn maybe_finish<'a, 'b>(net: DynNetMut<'a, 'b>, root: Arc) { + fn maybe_finish(net: DynNetMut<'_, '_>, root: Arc) { let Some(root) = Arc::into_inner(root) else { return }; (root)(net) } @@ -266,7 +261,7 @@ pub fn readback( from: Trg, f: impl FnOnce(DynNetMut, Tree) + Send + Sync + 'static, ) { - let root = UniqueTreePtr(Box::leak(Box::new(Tree::default()))); + let root = UniqueTreePtr(Box::leak(Box::default())); if M::LAZY { let from = net.wire_to_trg(from); diff --git a/src/trace.rs b/src/trace.rs index 466e3901..b0fba3b5 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -99,7 +99,7 @@ macro_rules! trace { impl $crate::trace::TraceSourceBearer for __ { const SOURCE: $crate::trace::TraceSource = $crate::trace::TraceSource { func: { - #[cfg(feature = "trace")] { std::any::type_name::<__>() } + #[cfg(feature = "trace")] { core::any::type_name::<__>() } #[cfg(not(feature = "trace"))] { "" } }, file: file!(), @@ -179,6 +179,7 @@ impl TraceData { } } +#[allow(clippy::vec_box)] // the address of `TraceLock` needs to remain stable static ACTIVE_TRACERS: Mutex>> = Mutex::new(Vec::new()); struct TraceWriter { @@ -207,7 +208,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() { - core::hint::spin_loop(); + hint::spin_loop(); } cb(unsafe { &mut *self.lock.data.get() }); self.lock.locked.store(false, Ordering::Release); @@ -299,7 +300,7 @@ pub fn _read_traces(limit: usize) { .enumerate() .map(|(i, t)| { while t.locked.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() { - core::hint::spin_loop(); + hint::spin_loop(); } TraceReader::new(unsafe { &*t.data.get() }, i) }) @@ -354,7 +355,7 @@ impl TraceArg for Wire { impl TraceArg for Trg { fn to_word(&self) -> u64 { - self.0.0 as u64 + self.0.0 } fn from_word(word: u64) -> impl Debug { Trg(Port(word)) @@ -465,8 +466,9 @@ pub fn set_hook() { if cfg!(feature = "trace") { #[cfg(feature = "std")] ONCE.call_once(|| { - let hook = std::panic::take_hook(); - std::panic::set_hook(Box::new(move |info| { + use std::panic; + let hook = panic::take_hook(); + panic::set_hook(Box::new(move |info| { hook(info); _read_traces(usize::MAX); })); diff --git a/src/transform.rs b/src/transform.rs index 2bd2c95b..3cfe021c 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -24,7 +24,7 @@ impl Book { } if passes.pre_reduce { if passes.eta_reduce { - for (_, def) in &mut self.nets { + for def in self.nets.values_mut() { def.eta_reduce(); } } @@ -34,7 +34,7 @@ impl Book { opts.pre_reduce_rewrites, ); } - for (_, def) in &mut self.nets { + for def in &mut self.nets.values_mut() { if passes.eta_reduce { def.eta_reduce(); } diff --git a/src/transform/coalesce_ctrs.rs b/src/transform/coalesce_ctrs.rs index aeb0cf3a..2bf7b770 100644 --- a/src/transform/coalesce_ctrs.rs +++ b/src/transform/coalesce_ctrs.rs @@ -16,7 +16,7 @@ impl Tree { Some(Tree::Ctr { lab: inner_lab, ports: inner_ports }) if inner_lab == lab && ports.len() + inner_ports.len() < MAX_ARITY => { - ports.extend(inner_ports.drain(..)); + ports.append(inner_ports); } Some(other) => ports.push(mem::take(other)), None => (), diff --git a/src/transform/eta_reduce.rs b/src/transform/eta_reduce.rs index 57c39c6f..89c09fc3 100644 --- a/src/transform/eta_reduce.rs +++ b/src/transform/eta_reduce.rs @@ -101,8 +101,7 @@ impl<'a> Phase1<'a> { } } Tree::Var { nam } => { - let nam: &str = &*nam; - if let Some(i) = self.vars.get(nam) { + if let Some(i) = self.vars.get(&**nam) { let j = self.nodes.len() as isize; self.nodes.push(NodeType::Var(*i as isize - j)); self.nodes[*i] = NodeType::Var(j - *i as isize); diff --git a/src/transform/pre_reduce.rs b/src/transform/pre_reduce.rs index 84855611..8eb86acc 100644 --- a/src/transform/pre_reduce.rs +++ b/src/transform/pre_reduce.rs @@ -59,7 +59,7 @@ impl Book { }; for nam in self.nets.keys() { - state.pre_reduce(&nam) + state.pre_reduce(nam) } let State { seen, rewrites, .. } = state; @@ -149,7 +149,7 @@ impl<'a> State<'a> { // Move interactions with inert defs back into the net redexes array self.captured_redexes.lock().drain(..).for_each(|r| rt.redux(r.0, r.1)); - let net = self.host.readback(&mut rt); + let net = self.host.readback(&rt); // Mutate the host in-place with the pre-reduced net. let instr = self.host.encode_def(&net); diff --git a/src/util/parse_abbrev_number.rs b/src/util/parse_abbrev_number.rs index edbbf013..32f31957 100644 --- a/src/util/parse_abbrev_number.rs +++ b/src/util/parse_abbrev_number.rs @@ -15,5 +15,5 @@ where Some(_) => (arg, 1), }; let base = base.parse::().map_err(|e| e.to_string())?; - Ok((base * scale).try_into().map_err(|e| format!("{:?}", e))?) + (base * scale).try_into().map_err(|e| format!("{:?}", e)) } diff --git a/src/util/stats.rs b/src/util/stats.rs index fa88c598..6b155556 100644 --- a/src/util/stats.rs +++ b/src/util/stats.rs @@ -1,8 +1,7 @@ use crate::prelude::*; -use core::time::Duration; - use crate::run::Rewrites; +use core::{str, time::Duration}; pub fn show_rewrites(rwts: &Rewrites) -> String { format!( @@ -25,12 +24,13 @@ pub fn show_stats(rwts: &Rewrites, elapsed: Duration) -> String { ) } +#[rustfmt::skip] // utterly unreadable on one line fn pretty_num(n: u64) -> String { n.to_string() .as_bytes() .rchunks(3) .rev() - .map(|x| core::str::from_utf8(x).unwrap()) + .map(|x| str::from_utf8(x).unwrap()) .flat_map(|x| ["_", x]) .skip(1) .collect() diff --git a/tests/cli.rs b/tests/cli.rs index e82f6246..d89ba9dc 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -14,7 +14,7 @@ use hvmc::{ use insta::assert_display_snapshot; fn get_arithmetic_program_path() -> String { - return env!("CARGO_MANIFEST_DIR").to_owned() + "/examples/arithmetic.hvmc"; + env!("CARGO_MANIFEST_DIR").to_owned() + "/examples/arithmetic.hvmc" } fn execute_hvmc(args: &[&str]) -> Result<(ExitStatus, String), Box> { @@ -216,35 +216,34 @@ fn test_apply_tree() { let root_port = run::Trg::port(run::Port::new_var(rnet.root.addr())); host.encode_net(&mut rnet, root_port, &fun); rnet.normal(); - let got_result = host.readback(&rnet); - got_result + host.readback(&rnet) } assert_display_snapshot!( - eval_with_args("(a a)", &vec!["(a a)"]), + eval_with_args("(a a)", &["(a a)"]), @"(a a)" ); assert_display_snapshot!( - eval_with_args("b & (a b) ~ a", &vec!["(a a)"]), + eval_with_args("b & (a b) ~ a", &["(a a)"]), @"a" ); assert_display_snapshot!( - eval_with_args("(z0 z0)", &vec!["(z1 z1)"]), + eval_with_args("(z0 z0)", &["(z1 z1)"]), @"(a a)" ); assert_display_snapshot!( - eval_with_args("(* #1)", &vec!["(a a)"]), + eval_with_args("(* #1)", &["(a a)"]), @"#1" ); assert_display_snapshot!( - eval_with_args("(<+ a b> (a b))", &vec!["#1", "#2"]), + eval_with_args("(<+ a b> (a b))", &["#1", "#2"]), @"#3" ); assert_display_snapshot!( - eval_with_args("(<* a b> (a b))", &vec!["#2", "#3"]), + eval_with_args("(<* a b> (a b))", &["#2", "#3"]), @"#6" ); assert_display_snapshot!( - eval_with_args("(<* a b> (a b))", &vec!["#2"]), + eval_with_args("(<* a b> (a b))", &["#2"]), @"(<* #2 a> a)" ); } @@ -254,7 +253,7 @@ fn test_cli_compile() { // Test normal-form expressions if !Command::new(env!("CARGO_BIN_EXE_hvmc")) - .args(&["compile", &get_arithmetic_program_path()]) + .args(["compile", &get_arithmetic_program_path()]) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn() @@ -268,7 +267,7 @@ fn test_cli_compile() { let mut output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); output_path.push("examples/arithmetic"); - let mut child = Command::new(&output_path).args(&["#40", "#3"]).stdout(Stdio::piped()).spawn().unwrap(); + let mut child = Command::new(&output_path).args(["#40", "#3"]).stdout(Stdio::piped()).spawn().unwrap(); let mut stdout = child.stdout.take().ok_or("Couldn't capture stdout!").unwrap(); child.wait().unwrap(); diff --git a/tests/fuzz.rs b/tests/fuzz.rs index 3d3ef5a4..651db8a9 100644 --- a/tests/fuzz.rs +++ b/tests/fuzz.rs @@ -23,11 +23,11 @@ fn fuzz_var_link_link_var() { let x = net.alloc(); let y = net.alloc(); let z = net.alloc(); - let a = Port::new_var(x.clone()); + let a = Port::new_var(x); let b = Port::new_var(x.other_half()); - let c = Port::new_var(y.clone()); + let c = Port::new_var(y); let d = Port::new_var(y.other_half()); - let e = Port::new_var(z.clone()); + let e = Port::new_var(z); let f = Port::new_var(z.other_half()); net.link_port_port(a.clone(), b.clone()); net.link_port_port(c.clone(), d.clone()); @@ -66,7 +66,7 @@ fn fuzz_pri_link_link_pri() { let heap = Heap::new_exact(16).unwrap(); let mut net = Net::new(&heap); let x = net.alloc(); - let a = Port::new_var(x.clone()); + let a = Port::new_var(x); let b = Port::new_var(x.other_half()); net.link_port_port(a.clone(), b.clone()); let mut nets = net.fork(2); @@ -98,9 +98,9 @@ fn fuzz_var_link_link_pri() { let mut net = Net::new(&heap); let x = net.alloc(); let y = net.alloc(); - let a = Port::new_var(x.clone()); + let a = Port::new_var(x); let b = Port::new_var(x.other_half()); - let c = Port::new_var(y.clone()); + let c = Port::new_var(y); let d = Port::new_var(y.other_half()); net.link_port_port(a.clone(), b.clone()); net.link_port_port(c.clone(), d.clone()); @@ -141,13 +141,13 @@ fn fuzz_var_link_link_link_var() { let y = net.alloc(); let z = net.alloc(); let w = net.alloc(); - let a = Port::new_var(x.clone()); + let a = Port::new_var(x); let b = Port::new_var(x.other_half()); - let c = Port::new_var(y.clone()); + let c = Port::new_var(y); let d = Port::new_var(y.other_half()); - let e = Port::new_var(z.clone()); + let e = Port::new_var(z); let f = Port::new_var(z.other_half()); - let g = Port::new_var(w.clone()); + let g = Port::new_var(w); let h = Port::new_var(w.other_half()); net.link_port_port(a.clone(), b.clone()); net.link_port_port(c.clone(), d.clone()); diff --git a/tests/lists.rs b/tests/lists.rs index f1dcfe2f..02d3ce0e 100644 --- a/tests/lists.rs +++ b/tests/lists.rs @@ -11,7 +11,7 @@ fn list_got(index: u32) -> Book { let def = book.get_mut("GenGotIndex").unwrap(); def.apply_tree(hvmc::ast::Tree::Ref { nam: format!("S{index}") }); let def = book.get_mut("main").unwrap(); - def.apply_tree(hvmc::ast::Tree::Ref { nam: format!("GenGotIndex") }); + def.apply_tree(hvmc::ast::Tree::Ref { nam: "GenGotIndex".to_string() }); book } @@ -22,7 +22,7 @@ fn list_put(index: u32, value: u32) -> Book { def.apply_tree(hvmc::ast::Tree::Ref { nam: format!("S{index}") }); def.apply_tree(hvmc::ast::Tree::Ref { nam: format!("S{value}") }); let def = book.get_mut("main").unwrap(); - def.apply_tree(hvmc::ast::Tree::Ref { nam: format!("GenPutIndexValue") }); + def.apply_tree(hvmc::ast::Tree::Ref { nam: "GenPutIndexValue".to_string() }); book } diff --git a/tests/tests.rs b/tests/tests.rs index bbde5091..8e5124e5 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -112,7 +112,7 @@ fn test_pre_reduce_run(path: &str, mut book: Book) { } fn test_path(path: &Path) { - let code = fs::read_to_string(&path).unwrap(); + let code = fs::read_to_string(path).unwrap(); let book = ast::Book::from_str(&code).unwrap(); let host = hvmc::stdlib::create_host(&book);