fix and refactor

This commit is contained in:
trimill 2024-03-07 19:38:57 -05:00
parent bc3fb597d5
commit 296ff666cb
Signed by: trimill
GPG Key ID: 4F77A16E17E10BCB
15 changed files with 138 additions and 114 deletions

1
Cargo.lock generated
View File

@ -772,6 +772,7 @@ dependencies = [
"lazy_static",
"num-complex",
"num-rational",
"num-traits",
"thiserror",
]

View File

@ -1,3 +1,7 @@
[workspace]
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
resolver = "2"
[profile.release-lto]
inherits = "release"
lto = "fat"

View File

@ -3,6 +3,10 @@ name = "talc-bin"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "talc"
path = "src/main.rs"
[dependencies]
talc-lang = { path = "../talc-lang" }
talc-std = { path = "../talc-std" }

View File

@ -106,7 +106,7 @@ impl Highlighter for TalcHelper {
}
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
Cow::Owned(format!("\x1b[37m{}\x1b[0m", hint))
Cow::Owned(format!("\x1b[37m{hint}\x1b[0m"))
}
fn highlight_char(&self, line: &str, _: usize, forced: bool) -> bool {

View File

@ -19,6 +19,10 @@ struct Args {
#[arg(short, long)]
disasm: bool,
/// show disassembled bytecode
#[arg(short='H', long)]
histfile: Option<PathBuf>,
/// enable or disable color
#[arg(short, long, default_value="auto")]
color: ColorChoice,

View File

@ -1,7 +1,7 @@
use std::{cell::RefCell, io::IsTerminal, process::ExitCode, rc::Rc};
use clap::ColorChoice;
use rustyline::{error::ReadlineError, history::MemHistory, ColorMode, Config, Editor};
use rustyline::{error::ReadlineError, history::{FileHistory, History}, ColorMode, Config, Editor};
use talc_lang::{compiler::compile_repl, symbol::Symbol, value::{function::disasm_recursive, Value}, Vm};
use crate::{helper::TalcHelper, Args};
@ -39,21 +39,30 @@ fn get_colmode(args: &Args) -> ColorMode {
}
}
pub fn init_rustyline(args: &Args) -> Result<Editor<TalcHelper, MemHistory>, ExitCode> {
pub fn init_rustyline(args: &Args) -> Result<Editor<TalcHelper, FileHistory>, ExitCode> {
let config = Config::builder()
.auto_add_history(true)
.color_mode(get_colmode(args))
.check_cursor_position(true)
.completion_type(rustyline::CompletionType::List)
.max_history_size(4096).unwrap()
.build();
match rustyline::Editor::with_history(config, MemHistory::default()) {
let mut hist = FileHistory::default();
if let Some(f) = &args.histfile {
if hist.load(f).is_err() {
eprintln!("Warn: failed to load history");
} else if hist.save(f).is_err() {
eprintln!("Warn: failed to save history");
}
}
match rustyline::Editor::with_history(config, hist) {
Ok(rl) => Ok(rl),
Err(ReadlineError::Io(e)) => {
eprintln!("Error: {e}");
eprintln!("Error creating repl: {e}");
Err(ExitCode::FAILURE)
},
Err(ReadlineError::Errno(e)) => {
eprintln!("Error: {e}");
eprintln!("Error creating repl: {e}");
Err(ExitCode::FAILURE)
},
Err(_) => Err(ExitCode::SUCCESS)
@ -75,7 +84,7 @@ pub fn repl(args: &Args) -> ExitCode {
interrupt.fetch_or(true, std::sync::atomic::Ordering::Relaxed);
});
if let Err(e) = ctrlc_res {
eprintln!("Warn: couldn't set ctrl+c handler: {e}")
eprintln!("Warn: couldn't set ctrl+c handler: {e}");
}
let prev1_sym = Symbol::get("_");
@ -98,6 +107,9 @@ pub fn repl(args: &Args) -> ExitCode {
rl.set_helper(Some(TalcHelper::new(vm.clone())));
loop {
if let Some(f) = &args.histfile {
let _ = rl.save_history(f);
}
let line = rl.readline(">> ");
let line = match line {
Ok(line) => line,

View File

@ -7,6 +7,7 @@ edition = "2021"
lalrpop-util = { version = "0.20", features = ["lexer", "unicode"] }
num-complex = "0.4"
num-rational = { version = "0.4", default-features = false, features = [] }
num-traits = "*"
thiserror = "1.0"
lazy_static = "1.4"

View File

@ -43,6 +43,7 @@ static TABLE: OnceLock<Mutex<SymbolTable>> = OnceLock::new();
const MAX_SYMBOL: usize = 0xff_ffff;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[repr(transparent)]
pub struct Symbol(u32);
fn get_table() -> &'static Mutex<SymbolTable> {

View File

@ -34,7 +34,7 @@ impl Value {
let col = col.clone();
let func = move |vm: &mut Vm, _| {
match vmcalliter!(vm; ii.clone())? {
Some(i) => Ok(col.index(i)?.to_cell()),
Some(i) => col.index(i),
None => Ok(Value::from(*SYM_END_ITERATION)),
}
};
@ -82,7 +82,7 @@ impl Value {
}
let end = tm.split_off(r.stop as usize);
tm.truncate(r.start as usize);
tm.extend(vals.into_iter().chain(end))
tm.extend(vals.into_iter().chain(end));
},
RangeType::Closed => {
if r.start < 0 || r.start > tm.len() as i64 {
@ -95,7 +95,7 @@ impl Value {
}
let end = tm.split_off(r.stop as usize + 1);
tm.truncate(r.start as usize);
tm.extend(vals.into_iter().chain(end))
tm.extend(vals.into_iter().chain(end));
},
RangeType::Endless => {
if r.start < 0 || r.start > tm.len() as i64 {
@ -103,7 +103,7 @@ impl Value {
"index {} out of bounds for list of length {}", r.stop, tm.len())
}
tm.truncate(r.start as usize);
tm.extend(vals)
tm.extend(vals);
},
}
Ok(())

View File

@ -7,6 +7,16 @@ use crate::{exception::{throw, Result}, symbol::{SYM_END_ITERATION, SYM_TYPE_ERR
use super::{function::{FuncAttrs, NativeFunc}, range::Range, HashValue, Value};
pub trait RatioExt {
fn to_f64(&self) -> f64;
}
impl RatioExt for Rational64 {
fn to_f64(&self) -> f64 {
num_traits::ToPrimitive::to_f64(self).unwrap_or(f64::NAN)
}
}
impl Value {
pub fn truthy(&self) -> bool {
match self {
@ -27,11 +37,6 @@ impl Value {
}
}
#[allow(clippy::cast_precision_loss)]
fn ratio_to_f64(r: Rational64) -> f64 {
*r.numer() as f64 / *r.denom() as f64
}
#[allow(clippy::cast_precision_loss)]
pub fn promote(a: Value, b: Value) -> (Value, Value) {
use Value as V;
@ -39,14 +44,14 @@ pub fn promote(a: Value, b: Value) -> (Value, Value) {
(V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b),
(V::Int(x), V::Float(..)) => (V::Float(*x as f64), b),
(V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b),
(V::Ratio(x), V::Float(..)) => (V::Float(ratio_to_f64(*x)), b),
(V::Ratio(x), V::Complex(..)) => (V::Complex(ratio_to_f64(*x).into()), b),
(V::Float(x), V::Complex(..)) => (V::Complex((*x).into()), b),
(V::Ratio(x), V::Float(..)) => (V::Float(x.to_f64()), b),
(V::Ratio(x), V::Complex(..)) => (V::Complex(x.to_f64().into()), b),
(V::Float(x), V::Complex(..)) => (V::Complex(x.into()), b),
(V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())),
(V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)),
(V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())),
(V::Float(..), V::Ratio(y)) => (a, V::Float(ratio_to_f64(*y))),
(V::Complex(..), V::Ratio(y)) => (a, V::Complex(ratio_to_f64(*y).into())),
(V::Float(..), V::Ratio(y)) => (a, V::Float(y.to_f64())),
(V::Complex(..), V::Ratio(y)) => (a, V::Complex(y.to_f64().into())),
(V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())),
_ => (a, b),
}
@ -183,7 +188,7 @@ impl Value {
(V::Float(x), V::Float(y))
=> Ok(V::Float(x.powf(y))),
(V::Ratio(x), V::Ratio(y))
=> Ok(V::Float(ratio_to_f64(x).powf(ratio_to_f64(y)))),
=> Ok(V::Float(x.to_f64().powf(y.to_f64()))),
(V::Complex(x), V::Complex(y))
=> Ok(V::Complex(x.powc(y))),
(l, r) => throw!(*SYM_TYPE_ERROR, "cannot exponentiate {l:#} and {r:#}")
@ -209,10 +214,10 @@ impl PartialEq for Value {
(V::Float(a), V::Int(b)) => *a == *b as f64,
(V::Int(a), V::Complex(b)) => Complex64::from(*a as f64) == *b,
(V::Complex(a), V::Int(b)) => *a == Complex64::from(*b as f64),
(V::Ratio(a), V::Float(b)) => ratio_to_f64(*a) == *b,
(V::Float(a), V::Ratio(b)) => *a == ratio_to_f64(*b),
(V::Ratio(a), V::Complex(b)) => Complex64::from(ratio_to_f64(*a)) == *b,
(V::Complex(a), V::Ratio(b)) => *a == Complex64::from(ratio_to_f64(*b)),
(V::Ratio(a), V::Float(b)) => a.to_f64() == *b,
(V::Float(a), V::Ratio(b)) => *a == b.to_f64(),
(V::Ratio(a), V::Complex(b)) => Complex64::from(a.to_f64()) == *b,
(V::Complex(a), V::Ratio(b)) => *a == Complex64::from(b.to_f64()),
(V::Float(a), V::Complex(b)) => Complex64::from(*a) == *b,
(V::Complex(a), V::Float(b)) => *a == Complex64::from(*b),
(V::String(a), V::String(b)) => *a == *b,
@ -246,8 +251,8 @@ impl PartialOrd for Value {
(V::Ratio(a), V::Int(b)) => a.partial_cmp(&Rational64::from(*b)),
(V::Int(a), V::Float(b)) => (*a as f64).partial_cmp(b),
(V::Float(a), V::Int(b)) => a.partial_cmp(&(*b as f64)),
(V::Ratio(a), V::Float(b)) => ratio_to_f64(*a).partial_cmp(b),
(V::Float(a), V::Ratio(b)) => a.partial_cmp(&ratio_to_f64(*b)),
(V::Ratio(a), V::Float(b)) => a.to_f64().partial_cmp(b),
(V::Float(a), V::Ratio(b)) => a.partial_cmp(&b.to_f64()),
(V::String(a), V::String(b)) => a.partial_cmp(b),
(V::List(a), V::List(b)) => a.borrow().partial_cmp(&*b.borrow()),
(V::Symbol(a), V::Symbol(b)) => a.partial_cmp(b),

View File

@ -296,7 +296,7 @@ impl Vm {
// [a0,a1...an] -.> [[a0,a1...an]]
I::NewList(n) => {
let list = self.pop_n(n as usize);
self.push(list.into())
self.push(list.into());
},
// [l,a0,a1...an] -.> [l ++ [a0,a1...an]]
I::GrowList(n) => {
@ -314,7 +314,7 @@ impl Vm {
let k = self.pop();
table.insert(k.try_into()?, v);
}
self.push(table.into())
self.push(table.into());
},
// [t,k0,v0...kn,vn] -> [t ++ {k0=v0...kn=vn}]
I::GrowTable(n) => {
@ -348,17 +348,17 @@ impl Vm {
// ip = n
I::Jump(n) => {
self.check_interrupt()?;
frame.ip = usize::from(n)
frame.ip = usize::from(n);
},
// [v] ->, [], if v then ip = n
I::JumpTrue(n) => if self.pop().truthy() {
self.check_interrupt()?;
frame.ip = usize::from(n)
frame.ip = usize::from(n);
},
// [v] ->, [], if not v then ip = n
I::JumpFalse(n) => if !self.pop().truthy() {
self.check_interrupt()?;
frame.ip = usize::from(n)
frame.ip = usize::from(n);
},
// [v] -> [iter(v)]
I::IterBegin => {
@ -368,12 +368,11 @@ impl Vm {
// [i,cell(v)] -> [i,v]
// [i,nil] -> [], ip = n
I::IterTest(n) => {
match self.pop().iter_unpack() {
Some(v) => self.push(v),
None => {
self.pop();
frame.ip = usize::from(n)
},
if let Some(v) = self.pop().iter_unpack() {
self.push(v);
} else {
self.pop();
frame.ip = usize::from(n);
}
},
// try_frames.push(t, stack.len())

View File

@ -132,7 +132,7 @@ pub fn tee(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
match vmcalliter!(vm; iter.clone())? {
Some(val) => {
vmcall!(vm; tee.clone(), val.clone())?;
Ok(val.into())
Ok(val)
}
None => Ok(Value::iter_pack(None)),
}
@ -170,7 +170,7 @@ pub fn filter(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
};
let res = vmcall!(vm; filter.clone(), next.clone())?;
if res.truthy() {
return Ok(next.into())
return Ok(next)
}
}
};
@ -198,7 +198,7 @@ pub fn take(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
return Ok(Value::iter_pack(None))
};
*taken.borrow_mut() += 1;
Ok(next.into())
Ok(next)
};
Ok(NativeFunc::new(Box::new(f), 0).into())
}
@ -262,22 +262,19 @@ pub fn cycle(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
}
let val = r.0[r.2].clone();
r.2 = (r.2 + 1) % r.0.len();
return Ok(val.into())
return Ok(val)
}
match vmcalliter!(vm; iter.clone())? {
Some(v) => {
record.borrow_mut().0.push(v.clone());
Ok(v.into())
},
None => {
let mut r = record.borrow_mut();
r.1 = true;
if r.0.is_empty() {
Ok(Value::iter_pack(None))
} else {
r.2 = (r.2 + 1) % r.0.len();
Ok(r.0[0].clone().into())
}
if let Some(v) = vmcalliter!(vm; iter.clone())? {
record.borrow_mut().0.push(v.clone());
Ok(v)
} else {
let mut r = record.borrow_mut();
r.1 = true;
if r.0.is_empty() {
Ok(Value::iter_pack(None))
} else {
r.2 = (r.2 + 1) % r.0.len();
Ok(r.0[0].clone())
}
}
};
@ -337,7 +334,7 @@ pub fn rev(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
if lst.borrow().is_none() {
let mut l = Vec::new();
while let Some(x) = vmcalliter!(vm; iter.clone())? {
l.push(x)
l.push(x);
}
*lst.borrow_mut() = Some(l);
}
@ -392,12 +389,11 @@ pub fn alternate(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
let n = s.0;
s.0 = (s.0 + 1) % iters.len();
drop(s);
match vmcalliter!(vm; iters[n].clone())? {
Some(v) => Ok(v),
None => {
state.borrow_mut().1 = true;
Ok(Value::iter_pack(None))
}
if let Some(v) = vmcalliter!(vm; iters[n].clone())? {
Ok(v)
} else {
state.borrow_mut().1 = true;
Ok(Value::iter_pack(None))
}
};
@ -417,25 +413,23 @@ pub fn intersperse(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
let state = RefCell::new(Intersperse::Init);
let f = move |vm: &mut Vm, _| {
match state.take() {
Intersperse::Init => match vmcalliter!(vm; iter.clone())? {
Some(v) => {
Intersperse::Init => {
if let Some(v) = vmcalliter!(vm; iter.clone())? {
*state.borrow_mut() = Intersperse::Waiting;
Ok(v)
},
None => {
} else {
*state.borrow_mut() = Intersperse::End;
Ok(Value::iter_pack(None))
},
}
},
Intersperse::Waiting => match vmcalliter!(vm; iter.clone())? {
Some(v) => {
Intersperse::Waiting => {
if let Some(v) = vmcalliter!(vm; iter.clone())? {
*state.borrow_mut() = Intersperse::HasNext(v);
Ok(val.clone())
},
None => {
} else {
*state.borrow_mut() = Intersperse::End;
Ok(Value::iter_pack(None))
},
}
},
Intersperse::HasNext(v) => {
*state.borrow_mut() = Intersperse::Waiting;
@ -460,12 +454,11 @@ pub fn chain(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
if *done_first.borrow() {
return vmcall!(vm; iter2.clone())
}
match vmcalliter!(vm; iter1.clone())? {
Some(v) => Ok(v),
None => {
*done_first.borrow_mut() = true;
vmcall!(vm; iter2.clone())
}
if let Some(v) = vmcalliter!(vm; iter1.clone())? {
Ok(v)
} else {
*done_first.borrow_mut() = true;
vmcall!(vm; iter2.clone())
}
};
@ -494,38 +487,36 @@ pub fn cartprod(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
}
if state.borrow().b_idx >= state.borrow().b_data.len() {
if !state.borrow().b_done {
let v = vmcalliter!(vm; b.clone())?;
let mut s = state.borrow_mut();
match v {
Some(x) => s.b_data.push(x),
None => {
s.b_done = true;
if s.b_idx == 0 {
s.done = true;
return Ok(Value::iter_pack(None))
}
s.b_idx = 0;
}
};
} else {
if state.borrow().b_done {
if state.borrow().b_idx == 0 {
state.borrow_mut().done = true;
return Ok(Value::Nil)
}
state.borrow_mut().b_idx = 0;
} else {
let v = vmcalliter!(vm; b.clone())?;
let mut s = state.borrow_mut();
if let Some(x) = v {
s.b_data.push(x)
} else {
s.b_done = true;
if s.b_idx == 0 {
s.done = true;
return Ok(Value::iter_pack(None))
}
s.b_idx = 0;
}
}
}
let b_res = state.borrow().b_data[state.borrow().b_idx].clone();
if state.borrow().b_idx == 0 {
match vmcalliter!(vm; a.clone())? {
Some(v) => state.borrow_mut().a_val = v,
None => {
state.borrow_mut().done = true;
return Ok(Value::iter_pack(None))
}
if let Some(v) = vmcalliter!(vm; a.clone())? {
state.borrow_mut().a_val = v
} else {
state.borrow_mut().done = true;
return Ok(Value::iter_pack(None))
}
}
@ -629,7 +620,7 @@ pub fn sum(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
let mut result = Value::Int(0);
while let Some(value) = vmcalliter!(vm; iter.clone())? {
result = (result + value)?
result = (result + value)?;
}
Ok(result)
}
@ -641,7 +632,7 @@ pub fn prod(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
let mut result = Value::Int(1);
while let Some(value) = vmcalliter!(vm; iter.clone())? {
result = (result * value)?
result = (result * value)?;
}
Ok(result)
}

View File

@ -124,10 +124,10 @@ fn to_radix_inner(n: i64, radix: u32) -> String {
if n < 0 {
result.push('-' as u32 as u8);
begin = 1;
x = (-n) as u64
x = (-n) as u64;
} else {
x = n as u64
};
x = n as u64;
}
loop {
let m = x % (radix as u64);
@ -360,9 +360,8 @@ pub fn factors(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
x /= 3;
factors.push(Value::Int(3));
}
//let lim = isqrt_inner(x);
let mut i = 5;
while x > 1 {
while x >= i*i {
while x % i == 0 {
x /= i;
factors.push(Value::Int(i));
@ -374,6 +373,9 @@ pub fn factors(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
}
i += 4;
}
if x > 1 {
factors.push(Value::Int(x));
}
Ok(factors.into())
}

View File

@ -53,7 +53,7 @@ pub fn rand_in(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
while let Some(v) = vmcalliter!(vm; iter.clone())? {
values.push(v);
}
if values.len() == 0 {
if values.is_empty() {
throw!(*SYM_TYPE_ERROR, "rand_in: empty iterator")
}
let i = rand::thread_rng().gen_range(0..values.len());

View File

@ -1,6 +1,6 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use talc_lang::{exception, parse_float, parse_int, symbol::SYM_TYPE_ERROR, throw, value::{HashValue, Rational64, Value}, Vm, exception::Result};
use talc_lang::{exception::Result, parse_float, parse_int, symbol::SYM_TYPE_ERROR, throw, exception, value::{ops::RatioExt, HashValue, Rational64, Value}, Vm};
use talc_macros::native_func;
use crate::unpack_args;
@ -49,7 +49,7 @@ pub fn as_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
if val.get_type() == ty {
return Ok(val)
}
match (val, ty.name().as_ref()) {
match (val, ty.name()) {
(_, "nil") => Ok(Value::Nil),
(v, "string") => Ok(Value::String(v.to_string().into())),
(v, "bool") => Ok(Value::Bool(v.truthy())),
@ -59,9 +59,9 @@ pub fn as_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
(Value::Int(x), "ratio") => Ok(Value::Ratio(x.into())),
(Value::Int(x), "float") => Ok(Value::Float(x as f64)),
(Value::Int(x), "complex") => Ok(Value::Complex((x as f64).into())),
(Value::Ratio(x), "int") => Ok(Value::Int(*x.numer() / *x.denom())),
(Value::Ratio(x), "float") => Ok(Value::Float(*x.numer() as f64 / *x.denom() as f64)),
(Value::Ratio(x), "complex") => Ok(Value::Complex((*x.numer() as f64 / *x.denom() as f64).into())),
(Value::Ratio(x), "int") => Ok(Value::Int(x.to_integer())),
(Value::Ratio(x), "float") => Ok(Value::Float(x.to_f64())),
(Value::Ratio(x), "complex") => Ok(Value::Complex(x.to_f64().into())),
(Value::Float(x), "int") => Ok(Value::Int(x as i64)),
(Value::Float(x), "ratio") => {
let r = Rational64::approximate_float(x)