This commit is contained in:
parent
668e0712c8
commit
b1fccce8e3
24 changed files with 276 additions and 165 deletions
19
Cargo.toml
19
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"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) => (),
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -99,7 +99,7 @@ fn read_init_file(args: &Args) -> Result<Option<String>, std::io::Error> {
|
|||
}
|
||||
|
||||
fn exec_line(
|
||||
vm: Rc<RefCell<Vm>>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -100,7 +100,7 @@ pub fn compile_repl(expr: &Expr, globals: &mut Vec<Symbol>) -> Result<Function>
|
|||
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(),
|
||||
));
|
||||
|
||||
|
|
|
@ -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<T> = std::result::Result<T, Exception>;
|
||||
|
||||
|
@ -18,7 +18,10 @@ impl Exception {
|
|||
Self { ty, msg }
|
||||
}
|
||||
|
||||
pub fn from_table(table: &Rc<RefCell<HashMap<HashValue, Value>>>) -> Option<Self> {
|
||||
pub fn from_value(value: &Value) -> Option<Self> {
|
||||
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<RefCell<HashMap<HashValue, Value>>> {
|
||||
let mut table = HashMap::new();
|
||||
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));
|
||||
Rc::new(RefCell::new(table))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -621,7 +621,7 @@ impl LString {
|
|||
#[derive(Clone)]
|
||||
pub struct Bytes<'a>(Copied<slice::Iter<'a, u8>>);
|
||||
|
||||
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<char, u8>;
|
||||
|
||||
#[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<Self::Item> {
|
||||
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<char, u8>);
|
||||
|
||||
#[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<Self::Item> {
|
||||
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<Self::Item> {
|
||||
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<Self::Item> {
|
||||
loop {
|
||||
if let (index, Ok(c)) = self.0.next_back()? {
|
||||
|
|
|
@ -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<i64> 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<Int> {
|
||||
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<u64> {
|
||||
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<u64> {
|
||||
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<u64> {
|
||||
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)
|
||||
|
|
|
@ -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<T: Clone>(&self, l: &mut Vec<T>, 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 {
|
||||
|
|
|
@ -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<Self>;
|
||||
}
|
||||
|
||||
|
@ -50,12 +53,10 @@ impl RatioExt for Ratio {
|
|||
}
|
||||
|
||||
fn approximate_float(x: f64) -> Option<Self> {
|
||||
match Rational64::approximate_float(x) {
|
||||
Some(r) => {
|
||||
if let Some(r) = Rational64::approximate_float(x) {
|
||||
let r = Ratio::new((*r.numer()).into(), (*r.denom()).into());
|
||||
Some(r)
|
||||
}
|
||||
None => {
|
||||
} else {
|
||||
let mut y = x;
|
||||
if y.abs() < 1.0 {
|
||||
y = 1.0 / y;
|
||||
|
@ -69,5 +70,4 @@ impl RatioExt for Ratio {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -77,18 +77,31 @@ impl Display for Value {
|
|||
}
|
||||
|
||||
impl Value {
|
||||
#[must_use]
|
||||
pub fn new_list(f: impl FnOnce(&mut Vec<Value>)) -> 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<HashValue, Value>)) -> 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,
|
||||
|
|
|
@ -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<Range> = 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<Self> {
|
||||
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>) -> Self {
|
||||
match v {
|
||||
Some(v) => v,
|
||||
|
|
|
@ -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,11 +411,9 @@ impl Vm {
|
|||
let Value::List(list) = list else {
|
||||
panic!("not a list")
|
||||
};
|
||||
match ext {
|
||||
Value::List(ext) => {
|
||||
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 {
|
||||
|
@ -427,10 +425,10 @@ impl Vm {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
|
|
@ -4,6 +4,9 @@ version = "0.2.1"
|
|||
edition = "2021"
|
||||
rust-version = "1.68.2"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -19,14 +19,11 @@ pub fn throw(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
|
||||
#[native_func(1)]
|
||||
pub fn rethrow(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
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) {
|
||||
|
|
|
@ -210,14 +210,11 @@ fn get_arg<'a>(
|
|||
n: Option<usize>,
|
||||
faidx: &mut usize,
|
||||
) -> Result<&'a Value> {
|
||||
let i = match n {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Int> {
|
||||
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<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
}
|
||||
if n.to_u32().is_some_and(|v| v == 1) {
|
||||
return Ok(Value::from(res))
|
||||
} else {
|
||||
}
|
||||
return Ok(Value::from(0))
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
pub fn ctz(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
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 {
|
||||
Ok(0.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
pub fn cto(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
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<Value>) -> Result<Value> {
|
||||
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<Value>) -> Result<Value> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -877,7 +877,7 @@ pub fn mean(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
sum / count
|
||||
}
|
||||
|
||||
fn variance_inner(vm: &mut Vm, iter: Value, pop: bool) -> Result<Value> {
|
||||
fn variance_inner(vm: &mut Vm, iter: &Value, pop: bool) -> Result<Value> {
|
||||
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<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
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)
|
||||
|
|
|
@ -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::<Vec<Value>>()
|
||||
|
@ -178,7 +178,10 @@ pub fn captures_once(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
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<Value>) -> Result<Value> {
|
|||
let re = regex_from(&re, "captures")?;
|
||||
Ok(re
|
||||
.captures_iter(s)
|
||||
.map(captures_to_value)
|
||||
.map(|cap| captures_to_value(&cap))
|
||||
.collect::<Vec<Value>>()
|
||||
.into())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue