From b1fccce8e3d0ca52c59f562ac9f4e768469f49cc Mon Sep 17 00:00:00 2001 From: trimill Date: Tue, 31 Dec 2024 22:09:51 -0500 Subject: [PATCH] refactoring --- Cargo.toml | 19 +++++++++ talc-bin/Cargo.toml | 3 ++ talc-bin/src/helper.rs | 4 +- talc-bin/src/main.rs | 2 +- talc-bin/src/repl.rs | 10 ++--- talc-lang/Cargo.toml | 3 ++ talc-lang/src/compiler.rs | 36 ++++++++--------- talc-lang/src/exception.rs | 19 +++++---- talc-lang/src/lib.rs | 6 --- talc-lang/src/lstring.rs | 22 +++++------ talc-lang/src/number/int.rs | 50 ++++++++++++++++++++---- talc-lang/src/number/range.rs | 26 +++---------- talc-lang/src/number/ratio.rs | 32 +++++++-------- talc-lang/src/optimize.rs | 12 +++--- talc-lang/src/value/mod.rs | 13 +++++++ talc-lang/src/value/ops.rs | 6 ++- talc-lang/src/vm.rs | 28 +++++++------- talc-macros/Cargo.toml | 3 ++ talc-std/Cargo.toml | 3 ++ talc-std/src/exception.rs | 11 ++---- talc-std/src/format.rs | 39 ++++++++----------- talc-std/src/ints.rs | 73 +++++++++++++++++++++++++++++++---- talc-std/src/iter.rs | 12 +++--- talc-std/src/regex.rs | 9 +++-- 24 files changed, 276 insertions(+), 165 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbc4fa2..ecfe00c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,24 @@ members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"] resolver = "2" + +[workspace.lints.clippy] +semicolon_if_nothing_returned = "warn" +allow_attributes = "warn" +inconsistent_struct_constructor = "warn" +uninlined_format_args = "warn" +single_match_else = "warn" +redundant_closure_for_method_calls = "warn" +redundant_closure = "warn" +redundant_closure_call = "warn" +map_unwrap_or = "warn" +map_clone = "warn" +manual_assert = "warn" +needless_pass_by_value = "warn" +unnested_or_patterns = "warn" +redundant_else = "warn" + + [profile.release-opt] inherits = "release" lto = "fat" @@ -10,3 +28,4 @@ codegen-units = 1 panic = "abort" + diff --git a/talc-bin/Cargo.toml b/talc-bin/Cargo.toml index 6a70332..6910760 100644 --- a/talc-bin/Cargo.toml +++ b/talc-bin/Cargo.toml @@ -4,6 +4,9 @@ version = "0.2.2" edition = "2021" rust-version = "1.81.0" +[lints] +workspace = true + [[bin]] name = "talc" path = "src/main.rs" diff --git a/talc-bin/src/helper.rs b/talc-bin/src/helper.rs index 07f811d..8efa9ae 100644 --- a/talc-bin/src/helper.rs +++ b/talc-bin/src/helper.rs @@ -86,7 +86,7 @@ impl Highlighter for TalcHelper { buf += format; buf += token.content; if !format.is_empty() { - buf += "\x1b[0m" + buf += "\x1b[0m"; } } buf += &line[(last.idx as usize)..]; @@ -126,7 +126,7 @@ impl Validator for TalcHelper { match k { K::Eof => break, K::LParen | K::LBrack | K::LBrace | K::If | K::While | K::For | K::Try => { - delims.push(token.kind) + delims.push(token.kind); } K::RParen => match delims.pop() { Some(K::LParen) => (), diff --git a/talc-bin/src/main.rs b/talc-bin/src/main.rs index 1b20a80..c93a152 100644 --- a/talc-bin/src/main.rs +++ b/talc-bin/src/main.rs @@ -68,7 +68,7 @@ fn exec(name: Symbol, src: &str, args: &Args) -> ExitCode { } if args.show_ast { - eprintln!("{}", ex); + eprintln!("{ex}"); } let func = match compile(&ex, Some(name)) { diff --git a/talc-bin/src/repl.rs b/talc-bin/src/repl.rs index 581f227..6050cbb 100644 --- a/talc-bin/src/repl.rs +++ b/talc-bin/src/repl.rs @@ -99,7 +99,7 @@ fn read_init_file(args: &Args) -> Result, std::io::Error> { } fn exec_line( - vm: Rc>, + vm: &mut Vm, line: &str, args: &Args, c: &ReplColors, @@ -118,7 +118,7 @@ fn exec_line( } if args.show_ast { - eprintln!("{}", ex); + eprintln!("{ex}"); } let func = match compile_repl(&ex, globals) { @@ -135,7 +135,7 @@ fn exec_line( } } - let mut vm = vm.borrow_mut(); + //let mut vm = vm.borrow_mut(); match vm.run_function(func.clone(), vec![func.into()]) { Ok(v) => { let prev2 = vm.get_global(*SYM_PREV2).unwrap().clone(); @@ -196,7 +196,7 @@ pub fn repl(args: &Args) -> ExitCode { rl.set_helper(Some(TalcHelper::new(vm.clone()))); if let Some(src) = init_src { - exec_line(vm.clone(), &src, args, &c, &mut globals); + exec_line(&mut vm.borrow_mut(), &src, args, &c, &mut globals); } loop { @@ -214,6 +214,6 @@ pub fn repl(args: &Args) -> ExitCode { } }; - exec_line(vm.clone(), &line, args, &c, &mut globals); + exec_line(&mut vm.borrow_mut(), &line, args, &c, &mut globals); } } diff --git a/talc-lang/Cargo.toml b/talc-lang/Cargo.toml index 692d47c..a13d3da 100644 --- a/talc-lang/Cargo.toml +++ b/talc-lang/Cargo.toml @@ -4,6 +4,9 @@ version = "0.2.2" edition = "2021" rust-version = "1.81.0" +[lints] +workspace = true + [dependencies] num = { version = "0.4", features = [] } lazy_static = "1.5" diff --git a/talc-lang/src/compiler.rs b/talc-lang/src/compiler.rs index 1972d7d..1e83959 100644 --- a/talc-lang/src/compiler.rs +++ b/talc-lang/src/compiler.rs @@ -100,7 +100,7 @@ pub fn compile_repl(expr: &Expr, globals: &mut Vec) -> Result Ok(comp.finish_repl(globals)) } -impl<'a> Default for Compiler<'a> { +impl Default for Compiler<'_> { fn default() -> Self { let mut scope = HashMap::new(); scope.insert(*SYM_SELF, VarKind::Local(0)); @@ -355,15 +355,13 @@ impl<'a> Compiler<'a> { self.emit(I::LoadClosedLocal(Arg24::from_usize(n))); } ResolveOutcome::InParent => { - let n = match self.closes.iter().position(|(n, _)| *n == name) { - Some(n) => n, - None => { - let n = self.closes.len(); - self.closes.push((name, n)); - n - } - }; - self.emit(I::LoadUpvalue(Arg24::from_usize(n))); + let pos = self.closes.iter().position(|(n, _)| *n == name); + let idx = pos.unwrap_or_else(|| { + let idx = self.closes.len(); + self.closes.push((name, idx)); + idx + }); + self.emit(I::LoadUpvalue(Arg24::from_usize(idx))); } ResolveOutcome::None | ResolveOutcome::Var(VarKind::Global) => { self.emit(I::LoadGlobal(Arg24::from_symbol(name))); @@ -412,15 +410,13 @@ impl<'a> Compiler<'a> { self.emit(I::StoreClosedLocal(Arg24::from_usize(n))); } ResolveOutcome::InParent => { - let n = match self.closes.iter().position(|(n, _)| *n == name) { - Some(n) => n, - None => { - let n = self.closes.len(); - self.closes.push((name, n)); - n - } - }; - self.emit(I::StoreUpvalue(Arg24::from_usize(n))); + let pos = self.closes.iter().position(|(n, _)| *n == name); + let idx = pos.unwrap_or_else(|| { + let idx = self.closes.len(); + self.closes.push((name, idx)); + idx + }); + self.emit(I::StoreUpvalue(Arg24::from_usize(idx))); } ResolveOutcome::Var(VarKind::Global) => { self.emit(I::StoreGlobal(Arg24::from_symbol(name))); @@ -878,7 +874,7 @@ impl<'a> Compiler<'a> { self.emit(I::ListDestructure( i.unwrap_or(len), - i.map(|n| len - n - 1).unwrap_or(0), + i.map_or(0, |n| len - n - 1), i.is_some(), )); diff --git a/talc-lang/src/exception.rs b/talc-lang/src/exception.rs index 2ef63a9..86e9c3d 100644 --- a/talc-lang/src/exception.rs +++ b/talc-lang/src/exception.rs @@ -1,9 +1,9 @@ use crate::{ lstring::LStr, symbol::{Symbol, SYM_MSG, SYM_TYPE}, - value::{HashValue, Value}, + value::Value, }; -use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc}; +use std::{fmt::Display, rc::Rc}; pub type Result = std::result::Result; @@ -18,7 +18,10 @@ impl Exception { Self { ty, msg } } - pub fn from_table(table: &Rc>>) -> Option { + pub fn from_value(value: &Value) -> Option { + let Value::Table(table) = value else { + return None + }; let table = table.borrow(); let ty = table.get(&(*SYM_TYPE).into())?; let msg = table.get(&(*SYM_MSG).into())?; @@ -32,11 +35,11 @@ impl Exception { } } - pub fn to_table(self) -> Rc>> { - let mut table = HashMap::new(); - table.insert((*SYM_TYPE).into(), self.ty.into()); - table.insert((*SYM_MSG).into(), Value::String(self.msg)); - Rc::new(RefCell::new(table)) + pub fn to_value(self) -> Value { + Value::new_table(|table| { + table.insert((*SYM_TYPE).into(), self.ty.into()); + table.insert((*SYM_MSG).into(), Value::String(self.msg)); + }) } } diff --git a/talc-lang/src/lib.rs b/talc-lang/src/lib.rs index 7f76322..1d4e3a8 100644 --- a/talc-lang/src/lib.rs +++ b/talc-lang/src/lib.rs @@ -1,9 +1,3 @@ -#![allow(clippy::mutable_key_type)] -#![warn(clippy::semicolon_if_nothing_returned)] -#![warn(clippy::allow_attributes)] -#![warn(clippy::inconsistent_struct_constructor)] -#![warn(clippy::uninlined_format_args)] - pub mod chunk; pub mod compiler; pub mod exception; diff --git a/talc-lang/src/lstring.rs b/talc-lang/src/lstring.rs index 98b8403..77e77fa 100644 --- a/talc-lang/src/lstring.rs +++ b/talc-lang/src/lstring.rs @@ -621,7 +621,7 @@ impl LString { #[derive(Clone)] pub struct Bytes<'a>(Copied>); -impl<'a> Iterator for Bytes<'a> { +impl Iterator for Bytes<'_> { type Item = u8; #[inline] @@ -662,19 +662,19 @@ impl<'a> Iterator for Bytes<'a> { } } -impl<'a> ExactSizeIterator for Bytes<'a> { +impl ExactSizeIterator for Bytes<'_> { #[inline] fn len(&self) -> usize { self.0.len() } } -impl<'a> FusedIterator for Bytes<'a> {} +impl FusedIterator for Bytes<'_> {} #[derive(Clone)] pub struct LosslessChars<'a>(&'a [u8]); -impl<'a> Iterator for LosslessChars<'a> { +impl Iterator for LosslessChars<'_> { type Item = Result; #[inline] @@ -691,7 +691,7 @@ impl<'a> Iterator for LosslessChars<'a> { } } -impl<'a> DoubleEndedIterator for LosslessChars<'a> { +impl DoubleEndedIterator for LosslessChars<'_> { fn next_back(&mut self) -> Option { let (new_bytes, res) = next_codepoint_back(self.0)?; self.0 = new_bytes; @@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for LosslessChars<'a> { #[derive(Clone)] pub struct LosslessCharsIndices<'a>(&'a [u8], usize); -impl<'a> Iterator for LosslessCharsIndices<'a> { +impl Iterator for LosslessCharsIndices<'_> { type Item = (usize, Result); #[inline] @@ -724,7 +724,7 @@ impl<'a> Iterator for LosslessCharsIndices<'a> { } } -impl<'a> DoubleEndedIterator for LosslessCharsIndices<'a> { +impl DoubleEndedIterator for LosslessCharsIndices<'_> { fn next_back(&mut self) -> Option { let (new_bytes, res) = next_codepoint_back(self.0)?; self.0 = new_bytes; @@ -739,7 +739,7 @@ impl<'a> DoubleEndedIterator for LosslessCharsIndices<'a> { #[derive(Clone)] pub struct Chars<'a>(LosslessChars<'a>); -impl<'a> Iterator for Chars<'a> { +impl Iterator for Chars<'_> { type Item = char; #[inline] @@ -757,7 +757,7 @@ impl<'a> Iterator for Chars<'a> { } } -impl<'a> DoubleEndedIterator for Chars<'a> { +impl DoubleEndedIterator for Chars<'_> { fn next_back(&mut self) -> Option { loop { if let Ok(c) = self.0.next_back()? { @@ -770,7 +770,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { #[derive(Clone)] pub struct CharsIndices<'a>(LosslessCharsIndices<'a>); -impl<'a> Iterator for CharsIndices<'a> { +impl Iterator for CharsIndices<'_> { type Item = (usize, char); #[inline] @@ -788,7 +788,7 @@ impl<'a> Iterator for CharsIndices<'a> { } } -impl<'a> DoubleEndedIterator for CharsIndices<'a> { +impl DoubleEndedIterator for CharsIndices<'_> { fn next_back(&mut self) -> Option { loop { if let (index, Ok(c)) = self.0.next_back()? { diff --git a/talc-lang/src/number/int.rs b/talc-lang/src/number/int.rs index b958045..a8e41a2 100644 --- a/talc-lang/src/number/int.rs +++ b/talc-lang/src/number/int.rs @@ -376,9 +376,7 @@ impl ops::Shl for &Int { type Output = Int; fn shl(self, rhs: Self) -> Self::Output { - if rhs.is_negative() { - panic!("attempt to shift left with negative") - } + assert!(!rhs.is_negative(), "attempt to shift left with negative"); let Some(rhs) = rhs.to_u32() else { panic!("shift left overflow") }; @@ -417,9 +415,7 @@ impl ops::ShlAssign for Int { impl ops::Shr for &Int { type Output = Int; fn shr(self, rhs: Self) -> Self::Output { - if rhs.is_negative() { - panic!("attempt to shift right with negative") - } + assert!(!rhs.is_negative(), "attempt to shift right with negative"); let Some(rhs) = rhs.to_u32() else { return Int::ZERO }; @@ -899,7 +895,7 @@ impl Int { } pub fn modinv(&self, modulus: &Int) -> Option { - self.to_big().modinv(&modulus.to_big()).map(|v| v.into()) + self.to_big().modinv(&modulus.to_big()).map(Into::into) } pub fn isignum(&self) -> i64 { @@ -926,6 +922,46 @@ impl Int { } } + pub fn trailing_ones(&self) -> Option { + match self.expand() { + IntType::Int(-1) => None, + IntType::Int(n) => Some(n.trailing_ones() as u64), + IntType::Big(n) => (!n).trailing_zeros(), + } + } + + pub fn count_zeros(&self) -> Option { + if !self.is_negative() { + return None + } + match self.expand() { + IntType::Int(n) => Some(n.count_zeros() as u64), + IntType::Big(n) => { + let mut count = 0; + for digit in n.iter_u64_digits() { + count += digit.count_zeros() as u64; + } + Some(count) + } + } + } + + pub fn count_ones(&self) -> Option { + if self.is_negative() { + return None + } + match self.expand() { + IntType::Int(n) => Some(n.count_ones() as u64), + IntType::Big(n) => { + let mut count = 0; + for digit in n.iter_u64_digits() { + count += digit.count_ones() as u64; + } + Some(count) + } + } + } + #[inline] pub fn eq_i64(&self, n: i64) -> bool { self.to_i64().is_some_and(|v| v == n) diff --git a/talc-lang/src/number/range.rs b/talc-lang/src/number/range.rs index 47f2958..a8977b7 100644 --- a/talc-lang/src/number/range.rs +++ b/talc-lang/src/number/range.rs @@ -119,7 +119,7 @@ impl Range { let Some(s) = &self.start else { return None }; Some(RangeIterator { cur: s.into(), - end: self.end.as_ref().map(|e| e.into()), + end: self.end.as_ref().map(Into::into), inclusive: self.inclusive, done: false, }) @@ -127,16 +127,8 @@ impl Range { pub fn index_slice<'a, T>(&self, l: &'a [T]) -> &'a [T] { let len = l.len(); - let s = self - .start - .as_ref() - .map(|s| to_slice_index(s, len)) - .unwrap_or(0); - let e = self - .end - .as_ref() - .map(|e| to_slice_index(e, len)) - .unwrap_or(len); + let s = self.start.as_ref().map_or(0, |s| to_slice_index(s, len)); + let e = self.end.as_ref().map_or(len, |e| to_slice_index(e, len)); let e = if self.inclusive { e.saturating_add(1).min(len) } else { @@ -150,16 +142,8 @@ impl Range { pub fn replace_range(&self, l: &mut Vec, rep: &[T]) { let len = l.len(); - let s = self - .start - .as_ref() - .map(|s| to_slice_index(s, len)) - .unwrap_or(0); - let e = self - .end - .as_ref() - .map(|e| to_slice_index(e, len)) - .unwrap_or(len); + let s = self.start.as_ref().map_or(0, |s| to_slice_index(s, len)); + let e = self.end.as_ref().map_or(len, |e| to_slice_index(e, len)); let e = if self.inclusive { e.saturating_add(1).min(len) } else { diff --git a/talc-lang/src/number/ratio.rs b/talc-lang/src/number/ratio.rs index e826189..b54601c 100644 --- a/talc-lang/src/number/ratio.rs +++ b/talc-lang/src/number/ratio.rs @@ -18,9 +18,12 @@ impl From<&Int> for Ratio { } pub trait RatioExt: Sized { + #[must_use] fn div_euclid(&self, n: &Self) -> Self; + #[must_use] fn rem_euclid(&self, n: &Self) -> Self; fn to_f64_uc(&self) -> f64; + #[must_use] fn approximate_float(x: f64) -> Option; } @@ -50,23 +53,20 @@ impl RatioExt for Ratio { } fn approximate_float(x: f64) -> Option { - match Rational64::approximate_float(x) { - Some(r) => { - let r = Ratio::new((*r.numer()).into(), (*r.denom()).into()); - Some(r) + if let Some(r) = Rational64::approximate_float(x) { + let r = Ratio::new((*r.numer()).into(), (*r.denom()).into()); + Some(r) + } else { + let mut y = x; + if y.abs() < 1.0 { + y = 1.0 / y; } - None => { - let mut y = x; - if y.abs() < 1.0 { - y = 1.0 / y; - } - let i = Int::from_f64(y)?; - let r = Ratio::from_integer(i.into()); - if x.abs() < 1.0 { - Some(r.recip()) - } else { - Some(r) - } + let i = Int::from_f64(y)?; + let r = Ratio::from_integer(i.into()); + if x.abs() < 1.0 { + Some(r.recip()) + } else { + Some(r) } } } diff --git a/talc-lang/src/optimize.rs b/talc-lang/src/optimize.rs index 2e767cd..996db69 100644 --- a/talc-lang/src/optimize.rs +++ b/talc-lang/src/optimize.rs @@ -50,10 +50,10 @@ fn optimize_ex(expr: &mut Expr) { fn optimize_ex_with(expr: &mut Expr, state: OptState) { let span = expr.span; match &mut expr.kind { - ExprKind::Literal(_) => (), - ExprKind::Ident(_) => (), - ExprKind::Var(_) => (), - ExprKind::Global(_) => (), + ExprKind::Literal(_) + | ExprKind::Ident(_) + | ExprKind::Var(_) + | ExprKind::Global(_) => (), ExprKind::UnaryOp(o, e) => { optimize_ex(e); if let Some(a) = e.value() { @@ -218,9 +218,7 @@ fn optimize_ex_with(expr: &mut Expr, state: OptState) { fn optimize_lv(e: &mut LValue) { match &mut e.kind { - LValueKind::Ident(_) => (), - LValueKind::Var(_) => (), - LValueKind::Global(_) => (), + LValueKind::Ident(_) | LValueKind::Var(_) | LValueKind::Global(_) => (), LValueKind::Index(l, r) => { optimize_ex(l); optimize_ex(r); diff --git a/talc-lang/src/value/mod.rs b/talc-lang/src/value/mod.rs index f8733d3..774cd82 100644 --- a/talc-lang/src/value/mod.rs +++ b/talc-lang/src/value/mod.rs @@ -77,18 +77,31 @@ impl Display for Value { } impl Value { + #[must_use] pub fn new_list(f: impl FnOnce(&mut Vec)) -> Self { let mut list = Vec::new(); f(&mut list); list.into() } + #[must_use] + #[expect(clippy::mutable_key_type)] pub fn new_table(f: impl FnOnce(&mut HashMap)) -> Self { let mut table = HashMap::new(); f(&mut table); table.into() } + #[must_use] + pub fn empty_list() -> Self { + Vec::new().into() + } + + #[must_use] + pub fn empty_table() -> Self { + HashMap::new().into() + } + pub fn write_to_lstring( &self, w: &mut LString, diff --git a/talc-lang/src/value/ops.rs b/talc-lang/src/value/ops.rs index 606945c..b900986 100644 --- a/talc-lang/src/value/ops.rs +++ b/talc-lang/src/value/ops.rs @@ -438,6 +438,7 @@ impl Value { Ok(V::String(s.into())) } (V::Table(t1), V::Table(t2)) => { + #[expect(clippy::mutable_key_type)] let mut t = t1.borrow().clone(); t.extend(t2.borrow().iter().map(|(k, v)| (k.clone(), v.clone()))); Ok(t.into()) @@ -508,13 +509,15 @@ impl Value { thread_local! { static RANGE_ALL: Rc = Rc::new(Range::range_all()); } - Self::Range(RANGE_ALL.with(|x| x.clone())) + Self::Range(RANGE_ALL.with(Clone::clone)) } + #[must_use] pub fn to_cell(self) -> Self { Value::Cell(Rc::new(RefCell::new(self))) } + #[must_use] pub fn iter_unpack(self) -> Option { match self { Self::Symbol(s) if s == *SYM_END_ITERATION => None, @@ -522,6 +525,7 @@ impl Value { } } + #[must_use] pub fn iter_pack(v: Option) -> Self { match v { Some(v) => v, diff --git a/talc-lang/src/vm.rs b/talc-lang/src/vm.rs index d291e12..2439b06 100644 --- a/talc-lang/src/vm.rs +++ b/talc-lang/src/vm.rs @@ -219,7 +219,7 @@ impl Vm { frame.ip = catch.addr; frame.locals.truncate(table.local_count); self.stack.truncate(try_frame.stack_len); - self.stack.push(Value::Table(exc.to_table())); + self.stack.push(exc.to_value()); return Ok(()) } } @@ -411,26 +411,24 @@ impl Vm { let Value::List(list) = list else { panic!("not a list") }; - match ext { - Value::List(ext) => { - list.borrow_mut().extend_from_slice(ext.borrow().as_slice()); - } - _ => { - let mut list = list.borrow_mut(); - let f = ext.to_iter_function()?; - loop { - self.push(f.clone()); - self.instr_call(0, frame)?; - match self.pop().iter_unpack() { - None => break, - Some(v) => list.push(v), - } + if let Value::List(ext) = ext { + list.borrow_mut().extend_from_slice(ext.borrow().as_slice()); + } else { + let mut list = list.borrow_mut(); + let f = ext.to_iter_function()?; + loop { + self.push(f.clone()); + self.instr_call(0, frame)?; + match self.pop().iter_unpack() { + None => break, + Some(v) => list.push(v), } } } self.push(Value::List(list)); } // [k0,v0...kn,vn] -.> [{k0=v0...kn=vn}] + #[expect(clippy::mutable_key_type)] I::NewTable(n) => { let n = n as usize; let mut table = HashMap::new(); diff --git a/talc-macros/Cargo.toml b/talc-macros/Cargo.toml index 6739e7c..b325c2e 100644 --- a/talc-macros/Cargo.toml +++ b/talc-macros/Cargo.toml @@ -4,6 +4,9 @@ version = "0.2.1" edition = "2021" rust-version = "1.68.2" +[lints] +workspace = true + [lib] proc-macro = true diff --git a/talc-std/Cargo.toml b/talc-std/Cargo.toml index 1ead113..d8a06a7 100644 --- a/talc-std/Cargo.toml +++ b/talc-std/Cargo.toml @@ -4,6 +4,9 @@ version = "0.2.2" edition = "2021" rust-version = "1.81.0" +[lints] +workspace = true + [dependencies] talc-lang = { path = "../talc-lang" } talc-macros = { path = "../talc-macros" } diff --git a/talc-std/src/exception.rs b/talc-std/src/exception.rs index 644ccf8..b17e093 100644 --- a/talc-std/src/exception.rs +++ b/talc-std/src/exception.rs @@ -19,14 +19,11 @@ pub fn throw(_: &mut Vm, args: Vec) -> Result { #[native_func(1)] pub fn rethrow(_: &mut Vm, args: Vec) -> Result { - let [_, table] = unpack_args!(args); - if let Value::Table(table) = table { - if let Some(e) = Exception::from_table(&table) { - return Err(e) - } + let [_, exc] = unpack_args!(args); + let Some(e) = Exception::from_value(&exc) else { throw!(*SYM_VALUE_ERROR, "rethrow: argument not a valid exception") - } - throw!(*SYM_TYPE_ERROR, "rethrow expected table") + }; + Err(e) } pub fn load(vm: &mut Vm) { diff --git a/talc-std/src/format.rs b/talc-std/src/format.rs index e91368d..f91c1d3 100644 --- a/talc-std/src/format.rs +++ b/talc-std/src/format.rs @@ -210,14 +210,11 @@ fn get_arg<'a>( n: Option, faidx: &mut usize, ) -> Result<&'a Value> { - let i = match n { - Some(n) => n, - None => { - let i = *faidx; - *faidx += 1; - i - } - }; + let i = n.unwrap_or_else(|| { + let i = *faidx; + *faidx += 1; + i + }); if i >= args.len() { throw!( *SYM_FORMAT_ERROR, @@ -259,13 +256,11 @@ fn format_float( let res = match (prec, ty) { (None, FmtType::Str) => write!(buf, "{}", Value::Float(f)), (None, FmtType::Repr) => write!(buf, "{:#}", Value::Float(f)), - (None, FmtType::Exp(true)) => write!(buf, "{:E}", f), - (None, FmtType::Exp(false)) => write!(buf, "{:e}", f), - (Some(p), FmtType::Str) | (Some(p), FmtType::Repr) => { - write!(buf, "{0:.1$}", f, p) - } - (Some(p), FmtType::Exp(true)) => write!(buf, "{0:.1$E}", f, p), - (Some(p), FmtType::Exp(false)) => write!(buf, "{0:.1$e}", f, p), + (None, FmtType::Exp(true)) => write!(buf, "{f:E}"), + (None, FmtType::Exp(false)) => write!(buf, "{f:e}"), + (Some(p), FmtType::Str | FmtType::Repr) => write!(buf, "{f:.p$}"), + (Some(p), FmtType::Exp(true)) => write!(buf, "{f:.p$E}"), + (Some(p), FmtType::Exp(false)) => write!(buf, "{f:.p$e}"), _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}"), }; res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) @@ -279,9 +274,9 @@ fn format_complex( ) -> Result<()> { format_float(cx.re, prec, ty, buf, "complex")?; if cx.im < 0.0 { - buf.push_char('-') + buf.push_char('-'); } else { - buf.push_char('+') + buf.push_char('+'); } format_float(cx.im.abs(), prec, ty, buf, "complex")?; Ok(()) @@ -298,7 +293,7 @@ fn format_int( throw!(*SYM_FORMAT_ERROR, "invalid format specifier for {ty_name}") } let res = match ty { - FmtType::Str | FmtType::Repr => write!(buf, "{}", n), + FmtType::Str | FmtType::Repr => write!(buf, "{n}"), FmtType::Hex(caps) => write!(buf, "{}", n.to_str_radix_case(16, caps)), FmtType::Oct => write!(buf, "{}", n.to_str_radix(8)), FmtType::Sex => write!(buf, "{}", n.to_str_radix(6)), @@ -330,8 +325,8 @@ fn format_value( throw!(*SYM_FORMAT_ERROR, "invalid format specifier for value") } let res = match ty { - FmtType::Str => write!(buf, "{}", v), - FmtType::Repr => write!(buf, "{:#}", v), + FmtType::Str => write!(buf, "{v}"), + FmtType::Repr => write!(buf, "{v:#}"), _ => throw!(*SYM_FORMAT_ERROR, "invalid format specifier for value"), }; res.map_err(|e| exception!(*SYM_FORMAT_ERROR, "{e}")) @@ -344,7 +339,7 @@ fn format_string( buf: &mut LString, ) -> Result<()> { if let Some(prec) = prec { - s = &s[..prec] + s = &s[..prec]; } let res = match ty { FmtType::Str => { @@ -359,7 +354,7 @@ fn format_string( fn pad_str(n: usize, c: char, buf: &mut LString) { for _ in 0..n { - buf.push_char(c) + buf.push_char(c); } } diff --git a/talc-std/src/ints.rs b/talc-std/src/ints.rs index 1ee3a7f..cc716d5 100644 --- a/talc-std/src/ints.rs +++ b/talc-std/src/ints.rs @@ -1,6 +1,6 @@ use talc_lang::{ exception::Result, - number::Int, + number::{Int, IntType}, prelude::*, symbol::{SYM_TYPE_ERROR, SYM_VALUE_ERROR}, throw, @@ -94,7 +94,7 @@ fn is_prime_inner(n: &Int) -> bool { fn pollard_rho(n: &Int, a: Int, b: &Int) -> Option { let mut x = a.clone(); - let mut y = a.clone(); + let mut y = a; let mut d = Int::ONE; while d.eq_i64(1) { x = &(&(&x * &x) + b) % n; @@ -194,6 +194,11 @@ pub fn load(vm: &mut Vm) { vm.set_global_name("iroot", iroot().into()); vm.set_global_name("jacobi", jacobi().into()); + + vm.set_global_name("ctz", ctz().into()); + vm.set_global_name("cto", cto().into()); + vm.set_global_name("bitcnt", bitcnt().into()); + vm.set_global_name("popcnt", popcnt().into()); } #[native_func(1)] @@ -239,9 +244,9 @@ pub fn totient(_: &mut Vm, args: Vec) -> Result { for factor in factorize(&n) { if last_factor != factor { res *= &factor - 1; - last_factor = factor + last_factor = factor; } else { - res *= factor + res *= factor; } } Ok(res.into()) @@ -391,9 +396,8 @@ pub fn jacobi(_: &mut Vm, args: Vec) -> Result { if n.is_zero() { if a.to_i32().is_some_and(|v| v == -1 || v == 1) { return Ok(Value::from(1)) - } else { - return Ok(Value::from(0)) } + return Ok(Value::from(0)) } // (k|l) = 0 if gcd(k,l) != 1 @@ -446,7 +450,62 @@ pub fn jacobi(_: &mut Vm, args: Vec) -> Result { } if n.to_u32().is_some_and(|v| v == 1) { return Ok(Value::from(res)) + } + return Ok(Value::from(0)) +} + +#[native_func(1)] +pub fn ctz(_: &mut Vm, args: Vec) -> Result { + let [_, n] = unpack_args!(args); + let Value::Int(n) = n else { + throw!(*SYM_TYPE_ERROR, "ctz expected integer, got {n:#}") + }; + if let Some(n) = n.trailing_zeros() { + Ok(Int::from(n).into()) } else { - return Ok(Value::from(0)) + Ok(0.into()) + } +} + +#[native_func(1)] +pub fn cto(_: &mut Vm, args: Vec) -> Result { + let [_, n] = unpack_args!(args); + let Value::Int(n) = n else { + throw!(*SYM_TYPE_ERROR, "cto expected integer, got {n:#}") + }; + if let Some(n) = n.trailing_ones() { + Ok(Int::from(n).into()) + } else { + Ok(0.into()) + } +} + +#[native_func(1)] +pub fn bitcnt(_: &mut Vm, args: Vec) -> Result { + let [_, n] = unpack_args!(args); + let Value::Int(n) = n else { + throw!(*SYM_TYPE_ERROR, "cto expected integer, got {n:#}") + }; + let cnt = match n.expand() { + IntType::Int(n) => 64 - n.leading_ones().max(n.leading_zeros()) as u64, + IntType::Big(b) => b.bits(), + }; + Ok(Int::from(cnt).into()) +} + +#[native_func(1)] +pub fn popcnt(_: &mut Vm, args: Vec) -> Result { + let [_, n] = unpack_args!(args); + let Value::Int(n) = n else { + throw!(*SYM_TYPE_ERROR, "cto expected integer, got {n:#}") + }; + if n.is_negative() { + // count_zeros always succeeds on negative numbers + let z = n.count_zeros().unwrap(); + Ok(Value::from(-(z as i64))) + } else { + // count_ones always succeeds on nonnegative numbers + let z = n.count_ones().unwrap(); + Ok(Value::from(z as i64)) } } diff --git a/talc-std/src/iter.rs b/talc-std/src/iter.rs index a38db6f..bc4dc09 100644 --- a/talc-std/src/iter.rs +++ b/talc-std/src/iter.rs @@ -877,7 +877,7 @@ pub fn mean(vm: &mut Vm, args: Vec) -> Result { sum / count } -fn variance_inner(vm: &mut Vm, iter: Value, pop: bool) -> Result { +fn variance_inner(vm: &mut Vm, iter: &Value, pop: bool) -> Result { let mut m = Value::Float(0.0); let mut s = Value::Float(0.0); let mut k = 1; @@ -895,7 +895,7 @@ pub fn variance(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - variance_inner(vm, iter, false) + variance_inner(vm, &iter, false) } #[native_func(1)] @@ -903,7 +903,7 @@ pub fn stdev(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let v = variance_inner(vm, iter, false)?; + let v = variance_inner(vm, &iter, false)?; Ok(match v { Value::Int(n) => Value::Float(n.to_f64_uc().sqrt()), Value::Float(f) => Value::Float(f.sqrt()), @@ -918,7 +918,7 @@ pub fn pvariance(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - variance_inner(vm, iter, true) + variance_inner(vm, &iter, true) } #[native_func(1)] @@ -926,7 +926,7 @@ pub fn pstdev(vm: &mut Vm, args: Vec) -> Result { let [_, iter] = unpack_args!(args); let iter = iter.to_iter_function()?; - let v = variance_inner(vm, iter, true)?; + let v = variance_inner(vm, &iter, true)?; Ok(match v { Value::Int(n) => Value::Float(n.to_f64_uc().sqrt()), Value::Float(f) => Value::Float(f.sqrt()), @@ -940,7 +940,7 @@ pub fn pstdev(vm: &mut Vm, args: Vec) -> Result { struct OrdValue(Value); impl std::cmp::Eq for OrdValue {} -#[allow(clippy::derive_ord_xor_partial_ord)] +#[expect(clippy::derive_ord_xor_partial_ord)] impl std::cmp::Ord for OrdValue { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Less) diff --git a/talc-std/src/regex.rs b/talc-std/src/regex.rs index 48ddead..5df9428 100644 --- a/talc-std/src/regex.rs +++ b/talc-std/src/regex.rs @@ -85,7 +85,7 @@ fn match_to_value(m: Match) -> Value { }) } -fn captures_to_value(cs: Captures) -> Value { +fn captures_to_value(cs: &Captures) -> Value { cs.iter() .map(|c| c.map_or(Value::Nil, match_to_value)) .collect::>() @@ -178,7 +178,10 @@ pub fn captures_once(_: &mut Vm, args: Vec) -> Result { throw!(*SYM_VALUE_ERROR, "search string must be valid UTF-8") }; let re = regex_from(&re, "captures_once")?; - Ok(re.captures(s).map_or(Value::Nil, captures_to_value)) + Ok(re + .captures(s) + .as_ref() + .map_or(Value::Nil, captures_to_value)) } #[native_func(2)] @@ -193,7 +196,7 @@ pub fn captures(_: &mut Vm, args: Vec) -> Result { let re = regex_from(&re, "captures")?; Ok(re .captures_iter(s) - .map(captures_to_value) + .map(|cap| captures_to_value(&cap)) .collect::>() .into()) }