fix and refactor
This commit is contained in:
parent
bc3fb597d5
commit
296ff666cb
15 changed files with 138 additions and 114 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -772,6 +772,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"num-complex",
|
"num-complex",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
|
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
[profile.release-lto]
|
||||||
|
inherits = "release"
|
||||||
|
lto = "fat"
|
||||||
|
|
|
@ -3,6 +3,10 @@ name = "talc-bin"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "talc"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
talc-lang = { path = "../talc-lang" }
|
talc-lang = { path = "../talc-lang" }
|
||||||
talc-std = { path = "../talc-std" }
|
talc-std = { path = "../talc-std" }
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl Highlighter for TalcHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
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 {
|
fn highlight_char(&self, line: &str, _: usize, forced: bool) -> bool {
|
||||||
|
|
|
@ -19,6 +19,10 @@ struct Args {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
disasm: bool,
|
disasm: bool,
|
||||||
|
|
||||||
|
/// show disassembled bytecode
|
||||||
|
#[arg(short='H', long)]
|
||||||
|
histfile: Option<PathBuf>,
|
||||||
|
|
||||||
/// enable or disable color
|
/// enable or disable color
|
||||||
#[arg(short, long, default_value="auto")]
|
#[arg(short, long, default_value="auto")]
|
||||||
color: ColorChoice,
|
color: ColorChoice,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{cell::RefCell, io::IsTerminal, process::ExitCode, rc::Rc};
|
use std::{cell::RefCell, io::IsTerminal, process::ExitCode, rc::Rc};
|
||||||
|
|
||||||
use clap::ColorChoice;
|
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 talc_lang::{compiler::compile_repl, symbol::Symbol, value::{function::disasm_recursive, Value}, Vm};
|
||||||
|
|
||||||
use crate::{helper::TalcHelper, Args};
|
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()
|
let config = Config::builder()
|
||||||
.auto_add_history(true)
|
.auto_add_history(true)
|
||||||
.color_mode(get_colmode(args))
|
.color_mode(get_colmode(args))
|
||||||
.check_cursor_position(true)
|
.check_cursor_position(true)
|
||||||
.completion_type(rustyline::CompletionType::List)
|
.completion_type(rustyline::CompletionType::List)
|
||||||
|
.max_history_size(4096).unwrap()
|
||||||
.build();
|
.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),
|
Ok(rl) => Ok(rl),
|
||||||
Err(ReadlineError::Io(e)) => {
|
Err(ReadlineError::Io(e)) => {
|
||||||
eprintln!("Error: {e}");
|
eprintln!("Error creating repl: {e}");
|
||||||
Err(ExitCode::FAILURE)
|
Err(ExitCode::FAILURE)
|
||||||
},
|
},
|
||||||
Err(ReadlineError::Errno(e)) => {
|
Err(ReadlineError::Errno(e)) => {
|
||||||
eprintln!("Error: {e}");
|
eprintln!("Error creating repl: {e}");
|
||||||
Err(ExitCode::FAILURE)
|
Err(ExitCode::FAILURE)
|
||||||
},
|
},
|
||||||
Err(_) => Err(ExitCode::SUCCESS)
|
Err(_) => Err(ExitCode::SUCCESS)
|
||||||
|
@ -75,7 +84,7 @@ pub fn repl(args: &Args) -> ExitCode {
|
||||||
interrupt.fetch_or(true, std::sync::atomic::Ordering::Relaxed);
|
interrupt.fetch_or(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
});
|
});
|
||||||
if let Err(e) = ctrlc_res {
|
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("_");
|
let prev1_sym = Symbol::get("_");
|
||||||
|
@ -98,6 +107,9 @@ pub fn repl(args: &Args) -> ExitCode {
|
||||||
rl.set_helper(Some(TalcHelper::new(vm.clone())));
|
rl.set_helper(Some(TalcHelper::new(vm.clone())));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if let Some(f) = &args.histfile {
|
||||||
|
let _ = rl.save_history(f);
|
||||||
|
}
|
||||||
let line = rl.readline(">> ");
|
let line = rl.readline(">> ");
|
||||||
let line = match line {
|
let line = match line {
|
||||||
Ok(line) => line,
|
Ok(line) => line,
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
lalrpop-util = { version = "0.20", features = ["lexer", "unicode"] }
|
lalrpop-util = { version = "0.20", features = ["lexer", "unicode"] }
|
||||||
num-complex = "0.4"
|
num-complex = "0.4"
|
||||||
num-rational = { version = "0.4", default-features = false, features = [] }
|
num-rational = { version = "0.4", default-features = false, features = [] }
|
||||||
|
num-traits = "*"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ static TABLE: OnceLock<Mutex<SymbolTable>> = OnceLock::new();
|
||||||
const MAX_SYMBOL: usize = 0xff_ffff;
|
const MAX_SYMBOL: usize = 0xff_ffff;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct Symbol(u32);
|
pub struct Symbol(u32);
|
||||||
|
|
||||||
fn get_table() -> &'static Mutex<SymbolTable> {
|
fn get_table() -> &'static Mutex<SymbolTable> {
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl Value {
|
||||||
let col = col.clone();
|
let col = col.clone();
|
||||||
let func = move |vm: &mut Vm, _| {
|
let func = move |vm: &mut Vm, _| {
|
||||||
match vmcalliter!(vm; ii.clone())? {
|
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)),
|
None => Ok(Value::from(*SYM_END_ITERATION)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -82,7 +82,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
let end = tm.split_off(r.stop as usize);
|
let end = tm.split_off(r.stop as usize);
|
||||||
tm.truncate(r.start as usize);
|
tm.truncate(r.start as usize);
|
||||||
tm.extend(vals.into_iter().chain(end))
|
tm.extend(vals.into_iter().chain(end));
|
||||||
},
|
},
|
||||||
RangeType::Closed => {
|
RangeType::Closed => {
|
||||||
if r.start < 0 || r.start > tm.len() as i64 {
|
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);
|
let end = tm.split_off(r.stop as usize + 1);
|
||||||
tm.truncate(r.start as usize);
|
tm.truncate(r.start as usize);
|
||||||
tm.extend(vals.into_iter().chain(end))
|
tm.extend(vals.into_iter().chain(end));
|
||||||
},
|
},
|
||||||
RangeType::Endless => {
|
RangeType::Endless => {
|
||||||
if r.start < 0 || r.start > tm.len() as i64 {
|
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())
|
"index {} out of bounds for list of length {}", r.stop, tm.len())
|
||||||
}
|
}
|
||||||
tm.truncate(r.start as usize);
|
tm.truncate(r.start as usize);
|
||||||
tm.extend(vals)
|
tm.extend(vals);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -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};
|
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 {
|
impl Value {
|
||||||
pub fn truthy(&self) -> bool {
|
pub fn truthy(&self) -> bool {
|
||||||
match self {
|
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)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
pub fn promote(a: Value, b: Value) -> (Value, Value) {
|
pub fn promote(a: Value, b: Value) -> (Value, Value) {
|
||||||
use Value as V;
|
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::Ratio(..)) => (V::Ratio((*x).into()), b),
|
||||||
(V::Int(x), V::Float(..)) => (V::Float(*x as f64), 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::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::Float(..)) => (V::Float(x.to_f64()), b),
|
||||||
(V::Ratio(x), V::Complex(..)) => (V::Complex(ratio_to_f64(*x).into()), b),
|
(V::Ratio(x), V::Complex(..)) => (V::Complex(x.to_f64().into()), b),
|
||||||
(V::Float(x), V::Complex(..)) => (V::Complex((*x).into()), b),
|
(V::Float(x), V::Complex(..)) => (V::Complex(x.into()), b),
|
||||||
(V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())),
|
(V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())),
|
||||||
(V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)),
|
(V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)),
|
||||||
(V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())),
|
(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::Float(..), V::Ratio(y)) => (a, V::Float(y.to_f64())),
|
||||||
(V::Complex(..), V::Ratio(y)) => (a, V::Complex(ratio_to_f64(*y).into())),
|
(V::Complex(..), V::Ratio(y)) => (a, V::Complex(y.to_f64().into())),
|
||||||
(V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())),
|
(V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())),
|
||||||
_ => (a, b),
|
_ => (a, b),
|
||||||
}
|
}
|
||||||
|
@ -183,7 +188,7 @@ impl Value {
|
||||||
(V::Float(x), V::Float(y))
|
(V::Float(x), V::Float(y))
|
||||||
=> Ok(V::Float(x.powf(y))),
|
=> Ok(V::Float(x.powf(y))),
|
||||||
(V::Ratio(x), V::Ratio(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))
|
(V::Complex(x), V::Complex(y))
|
||||||
=> Ok(V::Complex(x.powc(y))),
|
=> Ok(V::Complex(x.powc(y))),
|
||||||
(l, r) => throw!(*SYM_TYPE_ERROR, "cannot exponentiate {l:#} and {r:#}")
|
(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::Float(a), V::Int(b)) => *a == *b as f64,
|
||||||
(V::Int(a), V::Complex(b)) => Complex64::from(*a as f64) == *b,
|
(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::Complex(a), V::Int(b)) => *a == Complex64::from(*b as f64),
|
||||||
(V::Ratio(a), V::Float(b)) => ratio_to_f64(*a) == *b,
|
(V::Ratio(a), V::Float(b)) => a.to_f64() == *b,
|
||||||
(V::Float(a), V::Ratio(b)) => *a == ratio_to_f64(*b),
|
(V::Float(a), V::Ratio(b)) => *a == b.to_f64(),
|
||||||
(V::Ratio(a), V::Complex(b)) => Complex64::from(ratio_to_f64(*a)) == *b,
|
(V::Ratio(a), V::Complex(b)) => Complex64::from(a.to_f64()) == *b,
|
||||||
(V::Complex(a), V::Ratio(b)) => *a == Complex64::from(ratio_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::Float(a), V::Complex(b)) => Complex64::from(*a) == *b,
|
||||||
(V::Complex(a), V::Float(b)) => *a == Complex64::from(*b),
|
(V::Complex(a), V::Float(b)) => *a == Complex64::from(*b),
|
||||||
(V::String(a), V::String(b)) => *a == *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::Ratio(a), V::Int(b)) => a.partial_cmp(&Rational64::from(*b)),
|
||||||
(V::Int(a), V::Float(b)) => (*a as f64).partial_cmp(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::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::Ratio(a), V::Float(b)) => a.to_f64().partial_cmp(b),
|
||||||
(V::Float(a), V::Ratio(b)) => a.partial_cmp(&ratio_to_f64(*b)),
|
(V::Float(a), V::Ratio(b)) => a.partial_cmp(&b.to_f64()),
|
||||||
(V::String(a), V::String(b)) => a.partial_cmp(b),
|
(V::String(a), V::String(b)) => a.partial_cmp(b),
|
||||||
(V::List(a), V::List(b)) => a.borrow().partial_cmp(&*b.borrow()),
|
(V::List(a), V::List(b)) => a.borrow().partial_cmp(&*b.borrow()),
|
||||||
(V::Symbol(a), V::Symbol(b)) => a.partial_cmp(b),
|
(V::Symbol(a), V::Symbol(b)) => a.partial_cmp(b),
|
||||||
|
|
|
@ -296,7 +296,7 @@ impl Vm {
|
||||||
// [a0,a1...an] -.> [[a0,a1...an]]
|
// [a0,a1...an] -.> [[a0,a1...an]]
|
||||||
I::NewList(n) => {
|
I::NewList(n) => {
|
||||||
let list = self.pop_n(n as usize);
|
let list = self.pop_n(n as usize);
|
||||||
self.push(list.into())
|
self.push(list.into());
|
||||||
},
|
},
|
||||||
// [l,a0,a1...an] -.> [l ++ [a0,a1...an]]
|
// [l,a0,a1...an] -.> [l ++ [a0,a1...an]]
|
||||||
I::GrowList(n) => {
|
I::GrowList(n) => {
|
||||||
|
@ -314,7 +314,7 @@ impl Vm {
|
||||||
let k = self.pop();
|
let k = self.pop();
|
||||||
table.insert(k.try_into()?, v);
|
table.insert(k.try_into()?, v);
|
||||||
}
|
}
|
||||||
self.push(table.into())
|
self.push(table.into());
|
||||||
},
|
},
|
||||||
// [t,k0,v0...kn,vn] -> [t ++ {k0=v0...kn=vn}]
|
// [t,k0,v0...kn,vn] -> [t ++ {k0=v0...kn=vn}]
|
||||||
I::GrowTable(n) => {
|
I::GrowTable(n) => {
|
||||||
|
@ -348,17 +348,17 @@ impl Vm {
|
||||||
// ip = n
|
// ip = n
|
||||||
I::Jump(n) => {
|
I::Jump(n) => {
|
||||||
self.check_interrupt()?;
|
self.check_interrupt()?;
|
||||||
frame.ip = usize::from(n)
|
frame.ip = usize::from(n);
|
||||||
},
|
},
|
||||||
// [v] ->, [], if v then ip = n
|
// [v] ->, [], if v then ip = n
|
||||||
I::JumpTrue(n) => if self.pop().truthy() {
|
I::JumpTrue(n) => if self.pop().truthy() {
|
||||||
self.check_interrupt()?;
|
self.check_interrupt()?;
|
||||||
frame.ip = usize::from(n)
|
frame.ip = usize::from(n);
|
||||||
},
|
},
|
||||||
// [v] ->, [], if not v then ip = n
|
// [v] ->, [], if not v then ip = n
|
||||||
I::JumpFalse(n) => if !self.pop().truthy() {
|
I::JumpFalse(n) => if !self.pop().truthy() {
|
||||||
self.check_interrupt()?;
|
self.check_interrupt()?;
|
||||||
frame.ip = usize::from(n)
|
frame.ip = usize::from(n);
|
||||||
},
|
},
|
||||||
// [v] -> [iter(v)]
|
// [v] -> [iter(v)]
|
||||||
I::IterBegin => {
|
I::IterBegin => {
|
||||||
|
@ -368,12 +368,11 @@ impl Vm {
|
||||||
// [i,cell(v)] -> [i,v]
|
// [i,cell(v)] -> [i,v]
|
||||||
// [i,nil] -> [], ip = n
|
// [i,nil] -> [], ip = n
|
||||||
I::IterTest(n) => {
|
I::IterTest(n) => {
|
||||||
match self.pop().iter_unpack() {
|
if let Some(v) = self.pop().iter_unpack() {
|
||||||
Some(v) => self.push(v),
|
self.push(v);
|
||||||
None => {
|
} else {
|
||||||
self.pop();
|
self.pop();
|
||||||
frame.ip = usize::from(n)
|
frame.ip = usize::from(n);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// try_frames.push(t, stack.len())
|
// try_frames.push(t, stack.len())
|
||||||
|
|
|
@ -132,7 +132,7 @@ pub fn tee(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
match vmcalliter!(vm; iter.clone())? {
|
match vmcalliter!(vm; iter.clone())? {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
vmcall!(vm; tee.clone(), val.clone())?;
|
vmcall!(vm; tee.clone(), val.clone())?;
|
||||||
Ok(val.into())
|
Ok(val)
|
||||||
}
|
}
|
||||||
None => Ok(Value::iter_pack(None)),
|
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())?;
|
let res = vmcall!(vm; filter.clone(), next.clone())?;
|
||||||
if res.truthy() {
|
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))
|
return Ok(Value::iter_pack(None))
|
||||||
};
|
};
|
||||||
*taken.borrow_mut() += 1;
|
*taken.borrow_mut() += 1;
|
||||||
Ok(next.into())
|
Ok(next)
|
||||||
};
|
};
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
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();
|
let val = r.0[r.2].clone();
|
||||||
r.2 = (r.2 + 1) % r.0.len();
|
r.2 = (r.2 + 1) % r.0.len();
|
||||||
return Ok(val.into())
|
return Ok(val)
|
||||||
}
|
}
|
||||||
match vmcalliter!(vm; iter.clone())? {
|
if let Some(v) = vmcalliter!(vm; iter.clone())? {
|
||||||
Some(v) => {
|
|
||||||
record.borrow_mut().0.push(v.clone());
|
record.borrow_mut().0.push(v.clone());
|
||||||
Ok(v.into())
|
Ok(v)
|
||||||
},
|
} else {
|
||||||
None => {
|
|
||||||
let mut r = record.borrow_mut();
|
let mut r = record.borrow_mut();
|
||||||
r.1 = true;
|
r.1 = true;
|
||||||
if r.0.is_empty() {
|
if r.0.is_empty() {
|
||||||
Ok(Value::iter_pack(None))
|
Ok(Value::iter_pack(None))
|
||||||
} else {
|
} else {
|
||||||
r.2 = (r.2 + 1) % r.0.len();
|
r.2 = (r.2 + 1) % r.0.len();
|
||||||
Ok(r.0[0].clone().into())
|
Ok(r.0[0].clone())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -337,7 +334,7 @@ pub fn rev(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
if lst.borrow().is_none() {
|
if lst.borrow().is_none() {
|
||||||
let mut l = Vec::new();
|
let mut l = Vec::new();
|
||||||
while let Some(x) = vmcalliter!(vm; iter.clone())? {
|
while let Some(x) = vmcalliter!(vm; iter.clone())? {
|
||||||
l.push(x)
|
l.push(x);
|
||||||
}
|
}
|
||||||
*lst.borrow_mut() = Some(l);
|
*lst.borrow_mut() = Some(l);
|
||||||
}
|
}
|
||||||
|
@ -392,13 +389,12 @@ pub fn alternate(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let n = s.0;
|
let n = s.0;
|
||||||
s.0 = (s.0 + 1) % iters.len();
|
s.0 = (s.0 + 1) % iters.len();
|
||||||
drop(s);
|
drop(s);
|
||||||
match vmcalliter!(vm; iters[n].clone())? {
|
if let Some(v) = vmcalliter!(vm; iters[n].clone())? {
|
||||||
Some(v) => Ok(v),
|
Ok(v)
|
||||||
None => {
|
} else {
|
||||||
state.borrow_mut().1 = true;
|
state.borrow_mut().1 = true;
|
||||||
Ok(Value::iter_pack(None))
|
Ok(Value::iter_pack(None))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
Ok(NativeFunc::new(Box::new(f), 0).into())
|
||||||
|
@ -417,25 +413,23 @@ pub fn intersperse(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let state = RefCell::new(Intersperse::Init);
|
let state = RefCell::new(Intersperse::Init);
|
||||||
let f = move |vm: &mut Vm, _| {
|
let f = move |vm: &mut Vm, _| {
|
||||||
match state.take() {
|
match state.take() {
|
||||||
Intersperse::Init => match vmcalliter!(vm; iter.clone())? {
|
Intersperse::Init => {
|
||||||
Some(v) => {
|
if let Some(v) = vmcalliter!(vm; iter.clone())? {
|
||||||
*state.borrow_mut() = Intersperse::Waiting;
|
*state.borrow_mut() = Intersperse::Waiting;
|
||||||
Ok(v)
|
Ok(v)
|
||||||
},
|
} else {
|
||||||
None => {
|
|
||||||
*state.borrow_mut() = Intersperse::End;
|
*state.borrow_mut() = Intersperse::End;
|
||||||
Ok(Value::iter_pack(None))
|
Ok(Value::iter_pack(None))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
Intersperse::Waiting => {
|
||||||
Intersperse::Waiting => match vmcalliter!(vm; iter.clone())? {
|
if let Some(v) = vmcalliter!(vm; iter.clone())? {
|
||||||
Some(v) => {
|
|
||||||
*state.borrow_mut() = Intersperse::HasNext(v);
|
*state.borrow_mut() = Intersperse::HasNext(v);
|
||||||
Ok(val.clone())
|
Ok(val.clone())
|
||||||
},
|
} else {
|
||||||
None => {
|
|
||||||
*state.borrow_mut() = Intersperse::End;
|
*state.borrow_mut() = Intersperse::End;
|
||||||
Ok(Value::iter_pack(None))
|
Ok(Value::iter_pack(None))
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
Intersperse::HasNext(v) => {
|
Intersperse::HasNext(v) => {
|
||||||
*state.borrow_mut() = Intersperse::Waiting;
|
*state.borrow_mut() = Intersperse::Waiting;
|
||||||
|
@ -460,13 +454,12 @@ pub fn chain(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
if *done_first.borrow() {
|
if *done_first.borrow() {
|
||||||
return vmcall!(vm; iter2.clone())
|
return vmcall!(vm; iter2.clone())
|
||||||
}
|
}
|
||||||
match vmcalliter!(vm; iter1.clone())? {
|
if let Some(v) = vmcalliter!(vm; iter1.clone())? {
|
||||||
Some(v) => Ok(v),
|
Ok(v)
|
||||||
None => {
|
} else {
|
||||||
*done_first.borrow_mut() = true;
|
*done_first.borrow_mut() = true;
|
||||||
vmcall!(vm; iter2.clone())
|
vmcall!(vm; iter2.clone())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
Ok(NativeFunc::new(Box::new(f), 0).into())
|
||||||
|
@ -494,12 +487,18 @@ pub fn cartprod(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.borrow().b_idx >= state.borrow().b_data.len() {
|
if state.borrow().b_idx >= state.borrow().b_data.len() {
|
||||||
if !state.borrow().b_done {
|
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 v = vmcalliter!(vm; b.clone())?;
|
||||||
let mut s = state.borrow_mut();
|
let mut s = state.borrow_mut();
|
||||||
match v {
|
if let Some(x) = v {
|
||||||
Some(x) => s.b_data.push(x),
|
s.b_data.push(x)
|
||||||
None => {
|
} else {
|
||||||
s.b_done = true;
|
s.b_done = true;
|
||||||
if s.b_idx == 0 {
|
if s.b_idx == 0 {
|
||||||
s.done = true;
|
s.done = true;
|
||||||
|
@ -507,27 +506,19 @@ pub fn cartprod(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
s.b_idx = 0;
|
s.b_idx = 0;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if state.borrow().b_idx == 0 {
|
|
||||||
state.borrow_mut().done = true;
|
|
||||||
return Ok(Value::Nil)
|
|
||||||
}
|
|
||||||
state.borrow_mut().b_idx = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let b_res = state.borrow().b_data[state.borrow().b_idx].clone();
|
let b_res = state.borrow().b_data[state.borrow().b_idx].clone();
|
||||||
|
|
||||||
if state.borrow().b_idx == 0 {
|
if state.borrow().b_idx == 0 {
|
||||||
match vmcalliter!(vm; a.clone())? {
|
if let Some(v) = vmcalliter!(vm; a.clone())? {
|
||||||
Some(v) => state.borrow_mut().a_val = v,
|
state.borrow_mut().a_val = v
|
||||||
None => {
|
} else {
|
||||||
state.borrow_mut().done = true;
|
state.borrow_mut().done = true;
|
||||||
return Ok(Value::iter_pack(None))
|
return Ok(Value::iter_pack(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let a_res = state.borrow().a_val.clone();
|
let a_res = state.borrow().a_val.clone();
|
||||||
|
|
||||||
|
@ -629,7 +620,7 @@ pub fn sum(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
|
|
||||||
let mut result = Value::Int(0);
|
let mut result = Value::Int(0);
|
||||||
while let Some(value) = vmcalliter!(vm; iter.clone())? {
|
while let Some(value) = vmcalliter!(vm; iter.clone())? {
|
||||||
result = (result + value)?
|
result = (result + value)?;
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -641,7 +632,7 @@ pub fn prod(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
|
|
||||||
let mut result = Value::Int(1);
|
let mut result = Value::Int(1);
|
||||||
while let Some(value) = vmcalliter!(vm; iter.clone())? {
|
while let Some(value) = vmcalliter!(vm; iter.clone())? {
|
||||||
result = (result * value)?
|
result = (result * value)?;
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,10 +124,10 @@ fn to_radix_inner(n: i64, radix: u32) -> String {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
result.push('-' as u32 as u8);
|
result.push('-' as u32 as u8);
|
||||||
begin = 1;
|
begin = 1;
|
||||||
x = (-n) as u64
|
x = (-n) as u64;
|
||||||
} else {
|
} else {
|
||||||
x = n as u64
|
x = n as u64;
|
||||||
};
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let m = x % (radix as u64);
|
let m = x % (radix as u64);
|
||||||
|
@ -360,9 +360,8 @@ pub fn factors(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
x /= 3;
|
x /= 3;
|
||||||
factors.push(Value::Int(3));
|
factors.push(Value::Int(3));
|
||||||
}
|
}
|
||||||
//let lim = isqrt_inner(x);
|
|
||||||
let mut i = 5;
|
let mut i = 5;
|
||||||
while x > 1 {
|
while x >= i*i {
|
||||||
while x % i == 0 {
|
while x % i == 0 {
|
||||||
x /= i;
|
x /= i;
|
||||||
factors.push(Value::Int(i));
|
factors.push(Value::Int(i));
|
||||||
|
@ -374,6 +373,9 @@ pub fn factors(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
if x > 1 {
|
||||||
|
factors.push(Value::Int(x));
|
||||||
|
}
|
||||||
Ok(factors.into())
|
Ok(factors.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub fn rand_in(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
while let Some(v) = vmcalliter!(vm; iter.clone())? {
|
while let Some(v) = vmcalliter!(vm; iter.clone())? {
|
||||||
values.push(v);
|
values.push(v);
|
||||||
}
|
}
|
||||||
if values.len() == 0 {
|
if values.is_empty() {
|
||||||
throw!(*SYM_TYPE_ERROR, "rand_in: empty iterator")
|
throw!(*SYM_TYPE_ERROR, "rand_in: empty iterator")
|
||||||
}
|
}
|
||||||
let i = rand::thread_rng().gen_range(0..values.len());
|
let i = rand::thread_rng().gen_range(0..values.len());
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
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 talc_macros::native_func;
|
||||||
|
|
||||||
use crate::unpack_args;
|
use crate::unpack_args;
|
||||||
|
@ -49,7 +49,7 @@ pub fn as_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
if val.get_type() == ty {
|
if val.get_type() == ty {
|
||||||
return Ok(val)
|
return Ok(val)
|
||||||
}
|
}
|
||||||
match (val, ty.name().as_ref()) {
|
match (val, ty.name()) {
|
||||||
(_, "nil") => Ok(Value::Nil),
|
(_, "nil") => Ok(Value::Nil),
|
||||||
(v, "string") => Ok(Value::String(v.to_string().into())),
|
(v, "string") => Ok(Value::String(v.to_string().into())),
|
||||||
(v, "bool") => Ok(Value::Bool(v.truthy())),
|
(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), "ratio") => Ok(Value::Ratio(x.into())),
|
||||||
(Value::Int(x), "float") => Ok(Value::Float(x as f64)),
|
(Value::Int(x), "float") => Ok(Value::Float(x as f64)),
|
||||||
(Value::Int(x), "complex") => Ok(Value::Complex((x as f64).into())),
|
(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), "int") => Ok(Value::Int(x.to_integer())),
|
||||||
(Value::Ratio(x), "float") => Ok(Value::Float(*x.numer() as f64 / *x.denom() as f64)),
|
(Value::Ratio(x), "float") => Ok(Value::Float(x.to_f64())),
|
||||||
(Value::Ratio(x), "complex") => Ok(Value::Complex((*x.numer() as f64 / *x.denom() as f64).into())),
|
(Value::Ratio(x), "complex") => Ok(Value::Complex(x.to_f64().into())),
|
||||||
(Value::Float(x), "int") => Ok(Value::Int(x as i64)),
|
(Value::Float(x), "int") => Ok(Value::Int(x as i64)),
|
||||||
(Value::Float(x), "ratio") => {
|
(Value::Float(x), "ratio") => {
|
||||||
let r = Rational64::approximate_float(x)
|
let r = Rational64::approximate_float(x)
|
||||||
|
|
Loading…
Reference in a new issue