2024-02-27 00:18:43 -05:00
|
|
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
|
|
|
|
2024-11-04 13:25:31 -05:00
|
|
|
use talc_lang::{
|
|
|
|
exception::{exception, Result},
|
|
|
|
lformat,
|
|
|
|
parser::{parse_float, parse_int},
|
|
|
|
symbol::{symbol, Symbol, SYM_TYPE_ERROR, SYM_VALUE_ERROR},
|
|
|
|
throw,
|
|
|
|
value::{ops::RatioExt, HashValue, Rational64, Value},
|
|
|
|
Vm,
|
|
|
|
};
|
2024-02-27 00:18:43 -05:00
|
|
|
use talc_macros::native_func;
|
|
|
|
|
|
|
|
use crate::unpack_args;
|
|
|
|
|
|
|
|
pub fn load(vm: &mut Vm) {
|
|
|
|
vm.set_global_name("type", type_().into());
|
|
|
|
vm.set_global_name("is", is().into());
|
|
|
|
vm.set_global_name("as", as_().into());
|
|
|
|
vm.set_global_name("copy", copy().into());
|
|
|
|
|
|
|
|
vm.set_global_name("str", str_().into());
|
|
|
|
vm.set_global_name("repr", repr().into());
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
vm.set_global_name("symbol_name", symbol_name().into());
|
|
|
|
vm.set_global_name("symbol_of", symbol_of().into());
|
|
|
|
vm.set_global_name("symbol_exists", symbol_exists().into());
|
|
|
|
|
2024-02-27 00:18:43 -05:00
|
|
|
vm.set_global_name("cell", cell().into());
|
|
|
|
vm.set_global_name("uncell", uncell().into());
|
|
|
|
vm.set_global_name("cell_replace", cell_replace().into());
|
2024-11-03 12:50:36 -05:00
|
|
|
vm.set_global_name("cell_take", cell_take().into());
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
vm.set_global_name("func_state", func_state().into());
|
|
|
|
vm.set_global_name("func_arity", func_arity().into());
|
|
|
|
vm.set_global_name("func_name", func_name().into());
|
|
|
|
vm.set_global_name("apply", apply().into());
|
|
|
|
vm.set_global_name("compile", compile().into());
|
2024-02-27 00:18:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// types
|
|
|
|
//
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
#[native_func(1, "type")]
|
2024-02-27 00:18:43 -05:00
|
|
|
pub fn type_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
|
|
|
Ok(val.get_type().into())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(2)]
|
|
|
|
pub fn is(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val, ty] = unpack_args!(args);
|
|
|
|
let Value::Symbol(ty) = ty else {
|
|
|
|
throw!(*SYM_TYPE_ERROR, "type expected symbol, got {ty:#}")
|
|
|
|
};
|
|
|
|
Ok((val.get_type() == ty).into())
|
|
|
|
}
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
#[native_func(2, "as")]
|
2024-02-27 00:18:43 -05:00
|
|
|
pub fn as_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val, ty] = unpack_args!(args);
|
|
|
|
let Value::Symbol(ty) = ty else {
|
|
|
|
throw!(*SYM_TYPE_ERROR, "type expected symbol, got {ty:#}")
|
|
|
|
};
|
|
|
|
if val.get_type() == ty {
|
|
|
|
return Ok(val)
|
|
|
|
}
|
2024-03-30 12:21:09 -04:00
|
|
|
match (val, ty.name().as_bytes()) {
|
|
|
|
(_, b"nil") => Ok(Value::Nil),
|
|
|
|
(v, b"string") => Ok(Value::String(lformat!("{v}").into())),
|
|
|
|
(v, b"bool") => Ok(Value::Bool(v.truthy())),
|
|
|
|
|
|
|
|
(Value::Symbol(s), b"int") => Ok(Value::Int(s.id() as i64)),
|
|
|
|
|
|
|
|
(Value::Int(x), b"ratio") => Ok(Value::Ratio(x.into())),
|
|
|
|
(Value::Int(x), b"float") => Ok(Value::Float(x as f64)),
|
|
|
|
(Value::Int(x), b"complex") => Ok(Value::Complex((x as f64).into())),
|
|
|
|
(Value::Ratio(x), b"int") => Ok(Value::Int(x.to_integer())),
|
|
|
|
(Value::Ratio(x), b"float") => Ok(Value::Float(x.to_f64())),
|
|
|
|
(Value::Ratio(x), b"complex") => Ok(Value::Complex(x.to_f64().into())),
|
|
|
|
(Value::Float(x), b"int") => Ok(Value::Int(x as i64)),
|
|
|
|
(Value::Float(x), b"ratio") => {
|
2024-11-04 13:25:31 -05:00
|
|
|
let r = Rational64::approximate_float(x).ok_or_else(|| {
|
|
|
|
exception!(
|
|
|
|
*SYM_VALUE_ERROR,
|
|
|
|
"float {x:?} could not be converted to ratio"
|
|
|
|
)
|
|
|
|
})?;
|
2024-02-28 11:47:15 -05:00
|
|
|
Ok(Value::Ratio(r))
|
|
|
|
}
|
2024-03-30 12:21:09 -04:00
|
|
|
(Value::Float(x), b"complex") => Ok(Value::Complex(x.into())),
|
2024-02-27 00:18:43 -05:00
|
|
|
|
2024-11-04 13:25:31 -05:00
|
|
|
(Value::String(s), b"int") => parse_int(s.as_ref(), 10)
|
2024-03-30 12:21:09 -04:00
|
|
|
.map(i64::into)
|
2024-10-31 12:36:53 -04:00
|
|
|
.map_err(|_| exception!(*SYM_VALUE_ERROR, "could not parse {s:#} as integer")),
|
2024-02-27 00:18:43 -05:00
|
|
|
|
2024-11-04 13:25:31 -05:00
|
|
|
(Value::String(s), b"float") => parse_float(s.as_ref())
|
2024-03-30 12:21:09 -04:00
|
|
|
.map(f64::into)
|
2024-10-31 12:36:53 -04:00
|
|
|
.map_err(|_| exception!(*SYM_VALUE_ERROR, "could not parse {s:#} as float")),
|
2024-02-27 00:18:43 -05:00
|
|
|
|
2024-11-04 13:25:31 -05:00
|
|
|
(v, _) => throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"cannot convert value of type {} to type {}",
|
|
|
|
v.get_type().name(),
|
|
|
|
ty.name()
|
|
|
|
),
|
2024-02-27 00:18:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn copy_inner(value: Value) -> Result<Value> {
|
|
|
|
match value {
|
2024-11-04 13:25:31 -05:00
|
|
|
Value::Nil
|
|
|
|
| Value::Bool(_)
|
|
|
|
| Value::Symbol(_)
|
|
|
|
| Value::Int(_)
|
|
|
|
| Value::Ratio(_)
|
|
|
|
| Value::Float(_)
|
|
|
|
| Value::Complex(_)
|
|
|
|
| Value::Range(_)
|
|
|
|
| Value::String(_) => Ok(value),
|
2024-02-27 00:18:43 -05:00
|
|
|
Value::Cell(c) => {
|
2024-02-28 11:47:15 -05:00
|
|
|
let c = Rc::unwrap_or_clone(c).take();
|
2024-02-28 10:46:42 -05:00
|
|
|
let c = copy_inner(c)?;
|
2024-02-27 00:18:43 -05:00
|
|
|
Ok(RefCell::new(c).into())
|
2024-11-04 13:25:31 -05:00
|
|
|
}
|
2024-02-27 00:18:43 -05:00
|
|
|
Value::List(l) => {
|
2024-02-28 11:47:15 -05:00
|
|
|
let l = Rc::unwrap_or_clone(l).take();
|
2024-11-04 13:25:31 -05:00
|
|
|
let v: Result<Vec<Value>> = l.into_iter().map(copy_inner).collect();
|
2024-02-27 00:18:43 -05:00
|
|
|
Ok(v?.into())
|
2024-11-04 13:25:31 -05:00
|
|
|
}
|
2024-02-27 00:18:43 -05:00
|
|
|
Value::Table(t) => {
|
2024-02-28 11:47:15 -05:00
|
|
|
let t = Rc::unwrap_or_clone(t).take();
|
2024-11-04 13:25:31 -05:00
|
|
|
let v: Result<HashMap<HashValue, Value>> = t
|
|
|
|
.into_iter()
|
2024-02-27 00:18:43 -05:00
|
|
|
.map(|(k, v)| copy_inner(v).map(|v| (k, v)))
|
|
|
|
.collect();
|
|
|
|
Ok(v?.into())
|
2024-11-04 13:25:31 -05:00
|
|
|
}
|
2024-03-30 12:21:09 -04:00
|
|
|
Value::Native(ref n) => match n.copy_value()? {
|
|
|
|
Some(x) => Ok(x),
|
2024-11-04 13:25:31 -05:00
|
|
|
None => throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"cannot copy value of type {}",
|
|
|
|
value.get_type().name()
|
|
|
|
),
|
|
|
|
},
|
|
|
|
_ => throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"cannot copy value of type {}",
|
|
|
|
value.get_type().name()
|
|
|
|
),
|
2024-02-27 00:18:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn copy(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
|
|
|
copy_inner(val)
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// strings
|
|
|
|
//
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
#[native_func(1, "str")]
|
2024-02-27 00:18:43 -05:00
|
|
|
pub fn str_(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
2024-03-30 12:21:09 -04:00
|
|
|
Ok(lformat!("{val}").into())
|
2024-02-27 00:18:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn repr(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
2024-03-30 12:21:09 -04:00
|
|
|
Ok(lformat!("{val:#}").into())
|
2024-02-27 00:18:43 -05:00
|
|
|
}
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
//
|
|
|
|
// symbols
|
|
|
|
//
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn symbol_name(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
let Value::Symbol(s) = val else {
|
|
|
|
throw!(*SYM_TYPE_ERROR, "symbol_name: expected symbol")
|
|
|
|
};
|
2024-11-04 12:59:05 -05:00
|
|
|
Ok(s.name().into())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn symbol_of(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
let Value::String(s) = val else {
|
|
|
|
throw!(*SYM_TYPE_ERROR, "symbol_of: expected string")
|
|
|
|
};
|
2024-11-04 12:59:05 -05:00
|
|
|
Ok(Symbol::get(s.as_ref()).into())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn symbol_exists(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, val] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
let Value::String(s) = val else {
|
|
|
|
throw!(*SYM_TYPE_ERROR, "symbol_of: expected string")
|
|
|
|
};
|
2024-11-04 12:59:05 -05:00
|
|
|
match Symbol::try_get(s.as_ref()) {
|
2024-11-04 13:25:31 -05:00
|
|
|
Some(s) => Ok(s.into()),
|
|
|
|
None => Ok(Value::Nil),
|
|
|
|
}
|
2024-11-04 12:59:05 -05:00
|
|
|
}
|
|
|
|
|
2024-02-27 00:18:43 -05:00
|
|
|
//
|
|
|
|
// cells
|
|
|
|
//
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn cell(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, value] = unpack_args!(args);
|
|
|
|
Ok(RefCell::new(value).into())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn uncell(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, cell] = unpack_args!(args);
|
|
|
|
let Value::Cell(cell) = cell else {
|
2024-10-31 12:36:53 -04:00
|
|
|
throw!(*SYM_TYPE_ERROR, "uncell: value is not a cell")
|
2024-02-27 00:18:43 -05:00
|
|
|
};
|
|
|
|
Ok(Rc::unwrap_or_clone(cell).into_inner())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(2)]
|
|
|
|
pub fn cell_replace(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, cell, value] = unpack_args!(args);
|
|
|
|
let Value::Cell(cell) = cell else {
|
2024-10-31 12:36:53 -04:00
|
|
|
throw!(*SYM_TYPE_ERROR, "cell_replace: value is not a cell")
|
2024-02-27 00:18:43 -05:00
|
|
|
};
|
|
|
|
Ok(cell.replace(value))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn cell_take(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, cell] = unpack_args!(args);
|
|
|
|
let Value::Cell(cell) = cell else {
|
2024-10-31 12:36:53 -04:00
|
|
|
throw!(*SYM_TYPE_ERROR, "cell_take: value is not a cell")
|
2024-02-27 00:18:43 -05:00
|
|
|
};
|
|
|
|
Ok(cell.replace(Value::Nil))
|
|
|
|
}
|
|
|
|
|
2024-11-04 12:59:05 -05:00
|
|
|
//
|
|
|
|
// functions
|
|
|
|
//
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn func_state(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, func] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
match func {
|
|
|
|
Value::NativeFunc(_) => Ok(Value::Nil),
|
|
|
|
Value::Function(f) => {
|
|
|
|
let l: Vec<Value> = f.state.iter().map(|v| Value::Cell(v.clone())).collect();
|
|
|
|
Ok(l.into())
|
|
|
|
}
|
|
|
|
_ => throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"closure_state: {func:#} is not a talc function"
|
|
|
|
),
|
|
|
|
}
|
2024-11-04 12:59:05 -05:00
|
|
|
}
|
|
|
|
|
2024-11-03 12:50:36 -05:00
|
|
|
#[native_func(1)]
|
2024-11-04 12:59:05 -05:00
|
|
|
pub fn func_arity(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
2024-11-03 12:50:36 -05:00
|
|
|
let [_, func] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
let Some(attrs) = func.func_attrs() else {
|
2024-11-04 12:59:05 -05:00
|
|
|
throw!(*SYM_TYPE_ERROR, "closure_state: {func:#} is not a function")
|
2024-11-03 12:50:36 -05:00
|
|
|
};
|
2024-11-04 13:25:31 -05:00
|
|
|
Ok((attrs.arity as i64).into())
|
2024-11-04 12:59:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn func_name(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, func] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
let Some(attrs) = func.func_attrs() else {
|
2024-11-04 12:59:05 -05:00
|
|
|
throw!(*SYM_TYPE_ERROR, "closure_state: {func:#} is not a function")
|
|
|
|
};
|
2024-11-04 13:25:31 -05:00
|
|
|
if let Some(name) = attrs.name {
|
|
|
|
Ok(name.into())
|
|
|
|
} else {
|
|
|
|
Ok(Value::Nil)
|
|
|
|
}
|
2024-11-04 12:59:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(2)]
|
|
|
|
pub fn apply(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, func, lst] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
if func.func_attrs().is_none() {
|
|
|
|
throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"apply: first argument must be a function, found {func:#}"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
let Value::List(l) = lst else {
|
|
|
|
throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"apply: second argument must be a list, found {lst:#}"
|
|
|
|
)
|
|
|
|
};
|
|
|
|
let mut args = l.borrow().clone();
|
|
|
|
args.insert(0, func.clone());
|
|
|
|
vm.call_value(func, args)
|
2024-11-04 12:59:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[native_func(1)]
|
|
|
|
pub fn compile(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|
|
|
let [_, src] = unpack_args!(args);
|
2024-11-04 13:25:31 -05:00
|
|
|
let Value::String(src) = src else {
|
|
|
|
throw!(
|
|
|
|
*SYM_TYPE_ERROR,
|
|
|
|
"compile: argument must be a string, found {src:#}"
|
|
|
|
)
|
|
|
|
};
|
|
|
|
let src = src.to_str().map_err(|e| {
|
|
|
|
exception!(
|
|
|
|
*SYM_VALUE_ERROR,
|
|
|
|
"compile: argument must be valid unicode ({e})"
|
|
|
|
)
|
|
|
|
})?;
|
2024-11-04 13:31:53 -05:00
|
|
|
let ast = talc_lang::parser::parse(src)
|
|
|
|
.map_err(|e| exception!(symbol!("parse_error"), "{e}"))?;
|
2024-11-04 13:25:31 -05:00
|
|
|
let func = talc_lang::compiler::compile(&ast, None);
|
|
|
|
Ok(func.into())
|
2024-11-03 12:50:36 -05:00
|
|
|
}
|