a
This commit is contained in:
parent
2c54025d00
commit
bc3fb597d5
7 changed files with 72 additions and 73 deletions
|
@ -1,4 +1,3 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
|
members = ["talc-lang", "talc-bin", "talc-std", "talc-macros"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ impl Div<Value> for Value {
|
||||||
use Value as V;
|
use Value as V;
|
||||||
match promote(self, rhs) {
|
match promote(self, rhs) {
|
||||||
(_, V::Int(0)) => throw!(*SYM_TYPE_ERROR, "integer division by 0"),
|
(_, V::Int(0)) => throw!(*SYM_TYPE_ERROR, "integer division by 0"),
|
||||||
(_, V::Ratio(r)) if *r.numer() == 0 && *r.denom() != 0
|
(_, V::Ratio(r)) if *r.numer() == 0 && *r.denom() != 0
|
||||||
=> throw!(*SYM_TYPE_ERROR, "integer division by 0"),
|
=> throw!(*SYM_TYPE_ERROR, "integer division by 0"),
|
||||||
(V::Int(x), V::Int(y)) => Ok(V::Ratio(Rational64::new(x, y))),
|
(V::Int(x), V::Int(y)) => Ok(V::Ratio(Rational64::new(x, y))),
|
||||||
(V::Ratio(x), V::Ratio(y)) => Ok(V::Ratio(x / y)),
|
(V::Ratio(x), V::Ratio(y)) => Ok(V::Ratio(x / y)),
|
||||||
|
@ -326,12 +326,12 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_pack(v: Option<Self>) -> Self {
|
pub fn iter_pack(v: Option<Self>) -> Self {
|
||||||
match v {
|
match v {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => Value::from(*SYM_END_ITERATION)
|
None => Value::from(*SYM_END_ITERATION)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_iter_function(self) -> Result<Self> {
|
pub fn to_iter_function(self) -> Result<Self> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -340,7 +340,7 @@ impl Value {
|
||||||
let range_iter = RefCell::new(range.into_iter());
|
let range_iter = RefCell::new(range.into_iter());
|
||||||
let f = move |_: &mut Vm, _: Vec<Value>| -> Result<Value> {
|
let f = move |_: &mut Vm, _: Vec<Value>| -> Result<Value> {
|
||||||
Ok(Value::iter_pack(range_iter.borrow_mut().next()
|
Ok(Value::iter_pack(range_iter.borrow_mut().next()
|
||||||
.map(Value::from)))
|
.map(Value::from)))
|
||||||
};
|
};
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
Ok(NativeFunc::new(Box::new(f), 0).into())
|
||||||
},
|
},
|
||||||
|
@ -375,7 +375,7 @@ impl Value {
|
||||||
let keys = RefCell::new(keys.into_iter());
|
let keys = RefCell::new(keys.into_iter());
|
||||||
let f = move |_: &mut Vm, _: Vec<Value>| -> Result<Value> {
|
let f = move |_: &mut Vm, _: Vec<Value>| -> Result<Value> {
|
||||||
Ok(Value::iter_pack(keys.borrow_mut().next()
|
Ok(Value::iter_pack(keys.borrow_mut().next()
|
||||||
.map(HashValue::into_inner)))
|
.map(HashValue::into_inner)))
|
||||||
};
|
};
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
Ok(NativeFunc::new(Box::new(f), 0).into())
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,9 +17,9 @@ impl CallFrame {
|
||||||
Self {
|
Self {
|
||||||
func,
|
func,
|
||||||
locals,
|
locals,
|
||||||
try_frames: Vec::new(),
|
try_frames: Vec::new(),
|
||||||
ip: 0,
|
ip: 0,
|
||||||
root: false,
|
root: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ fn get_call_outcome(mut args: Vec<Value>) -> Result<CallOutcome> {
|
||||||
.expect("did not receive vararg") else {
|
.expect("did not receive vararg") else {
|
||||||
panic!("did not receive vararg")
|
panic!("did not receive vararg")
|
||||||
};
|
};
|
||||||
let varargs = Rc::unwrap_or_clone(varargs).take();
|
let varargs = Rc::unwrap_or_clone(varargs).take();
|
||||||
args.extend(varargs);
|
args.extend(varargs);
|
||||||
}
|
}
|
||||||
vm.call_value(f.clone(), args)
|
vm.call_value(f.clone(), args)
|
||||||
|
@ -407,8 +407,8 @@ impl Vm {
|
||||||
|
|
||||||
// safety: frame is restored immediately
|
// safety: frame is restored immediately
|
||||||
// after function call ends
|
// after function call ends
|
||||||
// ~25% performance improvement in
|
// ~25% performance improvement in
|
||||||
// code heavy on native function calls
|
// code heavy on native function calls
|
||||||
unsafe {
|
unsafe {
|
||||||
let f = std::ptr::read(frame);
|
let f = std::ptr::read(frame);
|
||||||
self.call_stack.push(f);
|
self.call_stack.push(f);
|
||||||
|
@ -416,16 +416,16 @@ impl Vm {
|
||||||
|
|
||||||
let res = (nf.func)(self, args);
|
let res = (nf.func)(self, args);
|
||||||
|
|
||||||
// safety: frame was referencing invalid memory due to
|
// safety: frame was referencing invalid memory due to
|
||||||
// previous unsafe block, write will fix that
|
// previous unsafe block, write will fix that
|
||||||
unsafe {
|
unsafe {
|
||||||
let f = self.call_stack.pop().expect("no frame to pop");
|
let f = self.call_stack.pop().expect("no frame to pop");
|
||||||
std::ptr::write(frame, f);
|
std::ptr::write(frame, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we restored the value of frame
|
// make sure we restored the value of frame
|
||||||
// before propagating exceptions
|
// before propagating exceptions
|
||||||
let res = res?;
|
let res = res?;
|
||||||
|
|
||||||
self.stack.push(res);
|
self.stack.push(res);
|
||||||
} else if let Value::Function(func) = &args[0] {
|
} else if let Value::Function(func) = &args[0] {
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn time_fn(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
vmcall!(vm; func)?;
|
vmcall!(vm; func)?;
|
||||||
let tf = SystemTime::now();
|
let tf = SystemTime::now();
|
||||||
let time = tf.duration_since(t0).expect("time went backwards");
|
let time = tf.duration_since(t0).expect("time went backwards");
|
||||||
Ok((time.as_secs_f64() as i64).into())
|
Ok(time.as_secs_f64().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(vm: &mut Vm) {
|
pub fn load(vm: &mut Vm) {
|
||||||
|
|
|
@ -148,12 +148,12 @@ pub fn scan(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let result = RefCell::new(init);
|
let result = RefCell::new(init);
|
||||||
let f = move |vm: &mut Vm, _| {
|
let f = move |vm: &mut Vm, _| {
|
||||||
let Some(val) = vmcalliter!(vm; iter.clone())? else {
|
let Some(val) = vmcalliter!(vm; iter.clone())? else {
|
||||||
result.take();
|
result.take();
|
||||||
return Ok(Value::iter_pack(None))
|
return Ok(Value::iter_pack(None))
|
||||||
};
|
};
|
||||||
let r = vmcall!(vm; func.clone(), result.take(), val)?;
|
let r = vmcall!(vm; func.clone(), result.take(), val)?;
|
||||||
*result.borrow_mut() = r.clone();
|
*result.borrow_mut() = r.clone();
|
||||||
Ok(r)
|
Ok(r)
|
||||||
};
|
};
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
Ok(NativeFunc::new(Box::new(f), 0).into())
|
||||||
}
|
}
|
||||||
|
@ -194,8 +194,8 @@ pub fn take(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
return Ok(Value::iter_pack(None))
|
return Ok(Value::iter_pack(None))
|
||||||
}
|
}
|
||||||
let Some(next) = vmcalliter!(vm; iter.clone())? else {
|
let Some(next) = vmcalliter!(vm; iter.clone())? else {
|
||||||
*taken.borrow_mut() = count;
|
*taken.borrow_mut() = count;
|
||||||
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.into())
|
||||||
|
@ -305,15 +305,15 @@ pub fn step(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let f = move |vm: &mut Vm, _| match state.take() {
|
let f = move |vm: &mut Vm, _| match state.take() {
|
||||||
Step::First => {
|
Step::First => {
|
||||||
let res = vmcalliter!(vm; iter.clone())?;
|
let res = vmcalliter!(vm; iter.clone())?;
|
||||||
if res.is_some() {
|
if res.is_some() {
|
||||||
*state.borrow_mut() = Step::Going;
|
*state.borrow_mut() = Step::Going;
|
||||||
}
|
}
|
||||||
Ok(Value::iter_pack(res))
|
Ok(Value::iter_pack(res))
|
||||||
},
|
},
|
||||||
Step::Going => {
|
Step::Going => {
|
||||||
for _ in 0..(by-1) {
|
for _ in 0..(by-1) {
|
||||||
if vmcall!(vm; iter.clone())? == Value::Nil {
|
if vmcall!(vm; iter.clone())? == Value::Nil {
|
||||||
return Ok(Value::iter_pack(None))
|
return Ok(Value::iter_pack(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let Some(x) = vmcalliter!(vm; iter.clone())? else {
|
let Some(x) = vmcalliter!(vm; iter.clone())? else {
|
||||||
|
@ -533,7 +533,7 @@ pub fn cartprod(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
|
|
||||||
state.borrow_mut().b_idx += 1;
|
state.borrow_mut().b_idx += 1;
|
||||||
|
|
||||||
Ok(Value::from(vec![a_res, b_res]).to_cell())
|
Ok(Value::from(vec![a_res, b_res]))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(NativeFunc::new(Box::new(f), 0).into())
|
Ok(NativeFunc::new(Box::new(f), 0).into())
|
||||||
|
@ -567,7 +567,7 @@ pub fn table(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let Value::List(l) = value else {
|
let Value::List(l) = value else {
|
||||||
throw!(*SYM_TYPE_ERROR, "table expected iterator to yield list")
|
throw!(*SYM_TYPE_ERROR, "table expected iterator to yield list")
|
||||||
};
|
};
|
||||||
let l = Rc::unwrap_or_clone(l).take();
|
let l = Rc::unwrap_or_clone(l).take();
|
||||||
let Ok([k, v]): std::result::Result<[Value; 2], Vec<Value>> = l.try_into() else {
|
let Ok([k, v]): std::result::Result<[Value; 2], Vec<Value>> = l.try_into() else {
|
||||||
throw!(*SYM_TYPE_ERROR, "table expected iterator to yield list of length 2")
|
throw!(*SYM_TYPE_ERROR, "table expected iterator to yield list of length 2")
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,42 +20,42 @@ pub fn rand_in(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let [_, col] = unpack_args!(args);
|
let [_, col] = unpack_args!(args);
|
||||||
match col {
|
match col {
|
||||||
Value::List(l) => {
|
Value::List(l) => {
|
||||||
let l = l.borrow();
|
let l = l.borrow();
|
||||||
let Some(v) = l.choose(&mut rand::thread_rng()) else {
|
let Some(v) = l.choose(&mut rand::thread_rng()) else {
|
||||||
throw!(*SYM_TYPE_ERROR, "rand_in: empty list")
|
throw!(*SYM_TYPE_ERROR, "rand_in: empty list")
|
||||||
};
|
};
|
||||||
Ok(v.clone())
|
Ok(v.clone())
|
||||||
},
|
},
|
||||||
Value::Table(t) => {
|
Value::Table(t) => {
|
||||||
let t = t.borrow();
|
let t = t.borrow();
|
||||||
if t.is_empty() {
|
if t.is_empty() {
|
||||||
throw!(*SYM_TYPE_ERROR, "rand_in: empty table")
|
throw!(*SYM_TYPE_ERROR, "rand_in: empty table")
|
||||||
};
|
};
|
||||||
let i = rand::thread_rng().gen_range(0..t.len());
|
let i = rand::thread_rng().gen_range(0..t.len());
|
||||||
let key = t.keys().nth(i).unwrap();
|
let key = t.keys().nth(i).unwrap();
|
||||||
Ok(key.clone().into_inner())
|
Ok(key.clone().into_inner())
|
||||||
},
|
},
|
||||||
Value::Range(r) => {
|
Value::Range(r) => {
|
||||||
if r.is_empty() {
|
if r.is_empty() {
|
||||||
throw!(*SYM_TYPE_ERROR, "rand_in: empty range")
|
throw!(*SYM_TYPE_ERROR, "rand_in: empty range")
|
||||||
}
|
}
|
||||||
match r.ty {
|
match r.ty {
|
||||||
RangeType::Open => Ok(Value::Int(
|
RangeType::Open => Ok(Value::Int(
|
||||||
rand::thread_rng().gen_range(r.start..r.stop))),
|
rand::thread_rng().gen_range(r.start..r.stop))),
|
||||||
RangeType::Closed => Ok(Value::Int(
|
RangeType::Closed => Ok(Value::Int(
|
||||||
rand::thread_rng().gen_range(r.start..=r.stop))),
|
rand::thread_rng().gen_range(r.start..=r.stop))),
|
||||||
RangeType::Endless => throw!(*SYM_TYPE_ERROR, "rand_in: endless range"),
|
RangeType::Endless => throw!(*SYM_TYPE_ERROR, "rand_in: endless range"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
col => {
|
col => {
|
||||||
let iter = col.to_iter_function()?;
|
let iter = col.to_iter_function()?;
|
||||||
let mut values = Vec::new();
|
let mut values = Vec::new();
|
||||||
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.len() == 0 {
|
||||||
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());
|
||||||
let v = values.swap_remove(i);
|
let v = values.swap_remove(i);
|
||||||
Ok(v)
|
Ok(v)
|
||||||
|
@ -66,9 +66,9 @@ pub fn rand_in(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
#[native_func(1)]
|
#[native_func(1)]
|
||||||
pub fn shuf(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
pub fn shuf(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
let [_, list] = unpack_args!(args);
|
let [_, list] = unpack_args!(args);
|
||||||
let Value::List(list) = list else {
|
let Value::List(list) = list else {
|
||||||
throw!(*SYM_TYPE_ERROR, "shuf expected list, got {list:#}")
|
throw!(*SYM_TYPE_ERROR, "shuf expected list, got {list:#}")
|
||||||
};
|
};
|
||||||
list.borrow_mut().shuffle(&mut rand::thread_rng());
|
list.borrow_mut().shuffle(&mut rand::thread_rng());
|
||||||
Ok(Value::List(list))
|
Ok(Value::List(list))
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,10 @@ pub fn as_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||||
(Value::Ratio(x), "complex") => Ok(Value::Complex((*x.numer() as f64 / *x.denom() as f64).into())),
|
(Value::Ratio(x), "complex") => Ok(Value::Complex((*x.numer() as f64 / *x.denom() as 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)
|
||||||
.ok_or_else(|| exception!(*SYM_TYPE_ERROR, "float {x:?} could not be converted to ratio"))?;
|
.ok_or_else(|| exception!(*SYM_TYPE_ERROR, "float {x:?} could not be converted to ratio"))?;
|
||||||
Ok(Value::Ratio(r))
|
Ok(Value::Ratio(r))
|
||||||
}
|
}
|
||||||
(Value::Float(x), "complex") => Ok(Value::Complex(x.into())),
|
(Value::Float(x), "complex") => Ok(Value::Complex(x.into())),
|
||||||
|
|
||||||
(Value::String(s), "int")
|
(Value::String(s), "int")
|
||||||
|
@ -92,19 +92,19 @@ pub fn copy_inner(value: Value) -> Result<Value> {
|
||||||
| Value::Complex(_) | Value::Range(_) | Value::String(_)
|
| Value::Complex(_) | Value::Range(_) | Value::String(_)
|
||||||
=> Ok(value),
|
=> Ok(value),
|
||||||
Value::Cell(c) => {
|
Value::Cell(c) => {
|
||||||
let c = Rc::unwrap_or_clone(c).take();
|
let c = Rc::unwrap_or_clone(c).take();
|
||||||
let c = copy_inner(c)?;
|
let c = copy_inner(c)?;
|
||||||
Ok(RefCell::new(c).into())
|
Ok(RefCell::new(c).into())
|
||||||
},
|
},
|
||||||
Value::List(l) => {
|
Value::List(l) => {
|
||||||
let l = Rc::unwrap_or_clone(l).take();
|
let l = Rc::unwrap_or_clone(l).take();
|
||||||
let v: Result<Vec<Value>> = l.into_iter()
|
let v: Result<Vec<Value>> = l.into_iter()
|
||||||
.map(copy_inner)
|
.map(copy_inner)
|
||||||
.collect();
|
.collect();
|
||||||
Ok(v?.into())
|
Ok(v?.into())
|
||||||
},
|
},
|
||||||
Value::Table(t) => {
|
Value::Table(t) => {
|
||||||
let t = Rc::unwrap_or_clone(t).take();
|
let t = Rc::unwrap_or_clone(t).take();
|
||||||
let v: Result<HashMap<HashValue, Value>> = t.into_iter()
|
let v: Result<HashMap<HashValue, Value>> = t.into_iter()
|
||||||
.map(|(k, v)| copy_inner(v).map(|v| (k, v)))
|
.map(|(k, v)| copy_inner(v).map(|v| (k, v)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
Loading…
Reference in a new issue