use std::cmp;
use std::f32;
use std::ffi::OsString;
use std::fs;
use std::fs::File;
use std::fs::create_dir;
use std::fs::read_dir;
use std::fs::remove_dir;
use std::fs::remove_file;
use std::io::BufWriter;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Write;
use std::io::stdin;
use std::io::stdout;
use std::io::stderr;
use std::mem::size_of;
use std::path;
use std::path::PathBuf;
use std::process::Command;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::Weak;
use opener::open_browser;
use rand::random;
use rand::random_range;
use crate::matrix::Matrix;
use crate::serde_json;
use crate::toml;
use crate::env::*;
use crate::error::*;
use crate::getopts::*;
use crate::interp::*;
use crate::io::*;
use crate::mod_node::*;
use crate::parser::*;
#[cfg(feature = "plot")]
use crate::plot::*;
use crate::utils::*;
use crate::value::*;
use crate::version::*;
fn fun1<F>(arg_values: &[Value], f: F) -> Result<Value>
where F: FnOnce(&Value) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value) => f(value),
None => Err(Error::Interp(String::from("no argument"))),
}
}
fn fun2<F>(arg_values: &[Value], f: F) -> Result<Value>
where F: FnOnce(&Value, &Value) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value), Some(value2)) => f(value, value2),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
fn fun1_for_f32_and_matrix_with_fun_refs<F, G>(arg_values: &[Value], err_msg: &str, f: &mut F, g: &mut G) -> Result<Value>
where F: FnMut(f32) -> f32,
G: FnMut(&Matrix) -> Result<Matrix>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value @ (Value::Int(_) | Value::Float(_))) => Ok(Value::Float(f(value.to_f32()))),
Some(Value::Object(object)) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(g(a)?)))),
_ => Err(Error::Interp(String::from(err_msg))),
}
},
Some(value) => value.dot1(err_msg, |a| fun1_for_f32_and_matrix_with_fun_refs(&[a.clone()], err_msg, f, g)),
None => Err(Error::Interp(String::from("no argument"))),
}
}
fn fun1_for_f32_and_matrix<F, G>(arg_values: &[Value], err_msg: &str, mut f: F, mut g: G) -> Result<Value>
where F: FnMut(f32) -> f32,
G: FnMut(&Matrix) -> Result<Matrix>
{ fun1_for_f32_and_matrix_with_fun_refs(arg_values, err_msg, &mut f, &mut g) }
fn fun2_for_f32_and_matrix_with_fun_refs<F, G, RG, H>(arg_values: &[Value], err_msg: &str, f: &mut F, g: &mut G, rg: &mut RG, h: &mut H) -> Result<Value>
where F: FnMut(f32, f32) -> f32,
G: FnMut(&Matrix, f32) -> Result<Matrix>,
RG: FnMut(&Matrix, f32) -> Result<Matrix>,
H: FnMut(&Matrix, &Matrix) -> Result<Matrix>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => Ok(Value::Float(f(value.to_f32(), value2.to_f32()))),
(Some(Value::Object(object)), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(g(a, value2.to_f32())?)))),
_ => Err(Error::Interp(String::from(err_msg))),
}
},
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(Value::Object(object2))) => {
match &**object2 {
Object::Matrix(b) => Ok(Value::Object(Arc::new(Object::Matrix(rg(b, value.to_f32())?)))),
_ => Err(Error::Interp(String::from(err_msg))),
}
},
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::Matrix(a), Object::Matrix(b)) => Ok(Value::Object(Arc::new(Object::Matrix(h(a, b)?)))),
_ => Err(Error::Interp(String::from(err_msg))),
}
},
(Some(value @ Value::Ref(_)), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => value.dot1(err_msg, |a| fun2_for_f32_and_matrix_with_fun_refs(&[a.clone(), value2.clone()], err_msg, f, g, rg, h)),
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ Value::Ref(_))) => value2.dot1(err_msg, |b| fun2_for_f32_and_matrix_with_fun_refs(&[value.clone(), b.clone()], err_msg, f, g, rg, h)),
(Some(value), Some(value2)) => value.dot2(value2, err_msg, |a, b| fun2_for_f32_and_matrix_with_fun_refs(&[a.clone(), b.clone()], err_msg, f, g, rg, h)),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
fn fun2_for_f32_and_matrix<F, G, RG, H>(arg_values: &[Value], err_msg: &str, mut f: F, mut g: G, mut rg: RG, mut h: H) -> Result<Value>
where F: FnMut(f32, f32) -> f32,
G: FnMut(&Matrix, f32) -> Result<Matrix>,
RG: FnMut(&Matrix, f32) -> Result<Matrix>,
H: FnMut(&Matrix, &Matrix) -> Result<Matrix>
{ fun2_for_f32_and_matrix_with_fun_refs(arg_values, err_msg, &mut f, &mut g, &mut rg, &mut h) }
fn get_first_arg_string(arg_values: &[Value], err_msg: &str) -> Result<String>
{
match arg_values.get(0) {
Some(arg_value) => {
match arg_value.to_opt_string() {
Some(s) => Ok(s),
None => Err(Error::Interp(String::from(err_msg))),
}
},
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn typ(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::None) => Ok(Value::Object(Arc::new(Object::String(String::from("none"))))),
Some(Value::Bool(_)) => Ok(Value::Object(Arc::new(Object::String(String::from("bool"))))),
Some(Value::Int(_)) => Ok(Value::Object(Arc::new(Object::String(String::from("int"))))),
Some(Value::Float(_)) => Ok(Value::Object(Arc::new(Object::String(String::from("float"))))),
Some(Value::Object(object)) => {
match &**object {
Object::String(_) => Ok(Value::Object(Arc::new(Object::String(String::from("string"))))),
Object::IntRange(_, _, _) => Ok(Value::Object(Arc::new(Object::String(String::from("intrange"))))),
Object::FloatRange(_, _, _) => Ok(Value::Object(Arc::new(Object::String(String::from("floatrange"))))),
Object::Matrix(_) => Ok(Value::Object(Arc::new(Object::String(String::from("matrix"))))),
Object::Fun(_, _, _) | Object::BuiltinFun(_, _) => Ok(Value::Object(Arc::new(Object::String(String::from("function"))))),
Object::MatrixArray(_, _, _, _) => Ok(Value::Object(Arc::new(Object::String(String::from("matrixarray"))))),
Object::MatrixRowSlice(_, _) => Ok(Value::Object(Arc::new(Object::String(String::from("matrixrowslice"))))),
Object::Error(_, _) => Ok(Value::Object(Arc::new(Object::String(String::from("error"))))),
Object::WindowId(_) => Ok(Value::Object(Arc::new(Object::String(String::from("windowid"))))),
}
},
Some(Value::Ref(object)) => {
let object_g = rw_lock_read(object)?;
match &*object_g {
MutObject::Array(_) => Ok(Value::Object(Arc::new(Object::String(String::from("array"))))),
MutObject::Struct(_) => Ok(Value::Object(Arc::new(Object::String(String::from("struct"))))),
}
},
Some(Value::Weak(_)) => Ok(Value::Object(Arc::new(Object::String(String::from("weak"))))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn clone(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Ref(object)) => {
let object_g = rw_lock_read(object)?;
Ok(Value::Ref(Arc::new(RwLock::new(object_g.clone()))))
},
Some(value) => Ok(value.clone()),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn boolean(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1(arg_values, |a| Ok(Value::Bool(a.to_bool()))) }
pub fn int(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1(arg_values, |a| Ok(Value::Int(a.to_i64()))) }
pub fn float(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1(arg_values, |a| Ok(Value::Float(a.to_f32()))) }
pub fn string(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1(arg_values, |a| Ok(Value::Object(Arc::new(Object::String(format!("{}", a)))))) }
fn checked_mul_row_count_and_col_count(row_count: i64, col_count: i64) -> Result<usize>
{
if row_count < 0 {
return Err(Error::Interp(String::from("number of rows is negative")));
}
if col_count < 0 {
return Err(Error::Interp(String::from("number of columns is negative")));
}
if row_count > (isize::MAX as i64) {
return Err(Error::Interp(String::from("too large number of rows")));
}
if col_count > (isize::MAX as i64) {
return Err(Error::Interp(String::from("too large number of columns")));
}
match row_count.checked_mul(col_count) {
Some(len) => {
if len > (isize::MAX as i64) {
return Err(Error::Interp(String::from("too large number of matrix elements")));
}
match (len as isize).checked_mul(size_of::<f32>() as isize) {
Some(_) => Ok(len as usize),
None => Err(Error::Interp(String::from("too large number of matrix elements"))),
}
},
None => Err(Error::Interp(String::from("too large number of matrix elements"))),
}
}
pub fn zeros(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(n_value @ (Value::Int(_) | Value::Float(_))), Some(m_value @ (Value::Int(_) | Value::Float(_)))) => {
let n = n_value.to_i64();
let m = m_value.to_i64();
checked_mul_row_count_and_col_count(n, m)?;
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_zeros(n as usize, m as usize)?))))
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function zeros"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn ones(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(n_value @ (Value::Int(_) | Value::Float(_))), Some(m_value @ (Value::Int(_) | Value::Float(_)))) => {
let n = n_value.to_i64();
let m = m_value.to_i64();
let len = checked_mul_row_count_and_col_count(n, m)?;
let xs = vec![1.0f32; len];
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(n as usize, m as usize, xs.as_slice())?))))
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function ones"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn eye(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(n_value @ (Value::Int(_) | Value::Float(_))) => {
let n = n_value.to_i64();
let len = checked_mul_row_count_and_col_count(n, n)?;
let mut xs = vec![0.0f32; len];
for i in 0..(n as usize) {
xs[i * (n as usize) + i] = 1.0;
}
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(n as usize, n as usize, xs.as_slice())?))))
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function eye"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn init(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 4 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2), arg_values.get(3)) {
(Some(n_value @ (Value::Int(_) | Value::Float(_))), Some(m_value @ (Value::Int(_) | Value::Float(_))), Some(data_value), Some(fun_value)) => {
let n = n_value.to_i64();
let m = m_value.to_i64();
let len = checked_mul_row_count_and_col_count(n, m)?;
let mut xs = vec![0.0f32; len];
for i in 0..(n as usize) {
for j in 0..(m as usize) {
match fun_value.apply(interp, env, &[data_value.clone(), Value::Int((i + 1) as i64), Value::Int((j + 1) as i64)])?.to_opt_f32() {
Some(x) => xs[i * (m as usize) + j] = x,
None => return Err(Error::Interp(String::from("can't convert value to floating-point number"))),
}
}
}
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(n as usize, m as usize, xs.as_slice())?))))
},
(Some(_), Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function init"))),
(_, _, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn initdiag(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(n_value @ (Value::Int(_) | Value::Float(_))), Some(data_value), Some(fun_value)) => {
let n = n_value.to_i64();
let len = checked_mul_row_count_and_col_count(n, n)?;
let mut xs = vec![0.0f32; len];
for i in 0..(n as usize) {
match fun_value.apply(interp, env, &[data_value.clone(), Value::Int((i + 1) as i64)])?.to_opt_f32() {
Some(x) => xs[i * (n as usize) + i] = x,
None => return Err(Error::Interp(String::from("can't convert value to floating-point number"))),
}
}
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(n as usize, n as usize, xs.as_slice())?))))
},
(Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function init"))),
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
fn to_row_or_column(value: &Value) -> Result<Vec<f32>>
{
match value.iter()? {
Some(mut iter) => {
let mut xs: Vec<f32> = Vec::new();
loop {
match iter.next() {
Some(Ok(elem)) => {
match elem.to_opt_f32() {
Some(x) => xs.push(x),
None => return Err(Error::Interp(String::from("can't convert value to floating-point number"))),
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(xs)
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
}
pub fn matrix(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let value = match arg_values.get(0) {
Some(tmp_value @ Value::Object(object)) => {
match &**object {
Object::Matrix(_) => return Ok(tmp_value.clone()),
_ => tmp_value,
}
},
Some(tmp_value) => tmp_value,
None => return Err(Error::Interp(String::from("no argument"))),
};
match value.iter()? {
Some(mut iter) => {
let mut xs: Vec<f32> = Vec::new();
let mut row_count = 0usize;
let mut col_count: Option<usize> = None;
loop {
match iter.next() {
Some(Ok(row_value)) => {
let ys = to_row_or_column(&row_value)?;
if col_count.map(|n| n == ys.len()).unwrap_or(true) {
xs.extend_from_slice(ys.as_slice());
col_count = Some(ys.len());
} else {
return Err(Error::Interp(String::from("numbers of columns of matrix rows aren't equal")));
}
match row_count.checked_add(1) {
Some(new_row_count) => row_count = new_row_count,
None => return Err(Error::Interp(String::from("too many matrix rows"))),
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(row_count, col_count.unwrap_or(0), xs.as_slice())?))))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
}
pub fn rowvector(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let value = match arg_values.get(0) {
Some(tmp_value @ Value::Object(object)) => {
match &**object {
Object::Matrix(a) => {
if a.row_count() == 1 {
return Ok(tmp_value.clone());
} else {
return Err(Error::Interp(String::from("number of rows isn't one")));
}
},
_ => tmp_value,
}
},
Some(tmp_value) => tmp_value,
None => return Err(Error::Interp(String::from("no argument"))),
};
let xs = to_row_or_column(&value)?;
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(1, xs.len(), xs.as_slice())?))))
}
pub fn colvector(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let value = match arg_values.get(0) {
Some(tmp_value @ Value::Object(object)) => {
match &**object {
Object::Matrix(a) => {
if a.col_count() == 1 {
return Ok(tmp_value.clone());
} else {
return Err(Error::Interp(String::from("number of columns isn't one")));
}
},
_ => tmp_value,
}
},
Some(tmp_value) => tmp_value,
None => return Err(Error::Interp(String::from("no argument"))),
};
let xs = to_row_or_column(&value)?;
Ok(Value::Object(Arc::new(Object::Matrix(matrix_create_and_set_elems(xs.len(), 1, xs.as_slice())?))))
}
pub fn matrixarray(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1(arg_values, Value::to_matrix_array) }
pub fn error(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(kind_object)), Some(Value::Object(msg_object))) => {
match (&**kind_object, &**msg_object) {
(Object::String(kind), Object::String(msg)) => Ok(Value::Object(Arc::new(Object::Error(kind.clone(), msg.clone())))),
(_, _) => Err(Error::Interp(String::from("unsupported types for function error"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function error"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn array(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let value = match arg_values.get(0) {
Some(tmp_value @ Value::Ref(object)) => {
let object_g = rw_lock_read(object)?;
match &*object_g {
MutObject::Array(_) => return Ok(tmp_value.clone()),
_ => tmp_value,
}
},
Some(tmp_value) => tmp_value,
None => return Err(Error::Interp(String::from("no argument"))),
};
match value.iter()? {
Some(mut iter) => {
let mut elems: Vec<Value> = Vec::new();
loop {
match iter.next() {
Some(Ok(elem)) => elems.push(elem),
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(elems)))))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
}
pub fn strong(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value @ Value::Ref(_)) => Ok(value.clone()),
Some(Value::Weak(object)) => {
match object.upgrade() {
Some(object) => Ok(Value::Ref(object)),
None => Ok(Value::None),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported types for function strong"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn weak(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() > 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Ref(object)) => Ok(Value::Weak(Arc::downgrade(object))),
Some(value @ Value::Weak(_)) => Ok(value.clone()),
Some(_) => Err(Error::Interp(String::from("unsupported types for function weak"))),
None => Ok(Value::Weak(Weak::new())),
}
}
pub fn isempty(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => Ok(Value::Bool(s.is_empty())),
Object::MatrixArray(row_count, _, _, _) => Ok(Value::Bool(*row_count == 0)),
Object::MatrixRowSlice(matrix_array, _) => {
match &**matrix_array {
Object::MatrixArray(_, col_count, _, _) => Ok(Value::Bool(*col_count == 0)),
_ => Err(Error::Interp(String::from("invalid matrix array type"))),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function isempty"))),
}
},
Some(Value::Ref(object)) => {
let object_g = rw_lock_read(object)?;
match &*object_g {
MutObject::Array(elems) => Ok(Value::Bool(elems.is_empty())),
_ => Err(Error::Interp(String::from("unsupported type for function isempty"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function isempty"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn length(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => Ok(Value::Int(s.chars().count() as i64)),
Object::MatrixArray(row_count, _, _, _) => Ok(Value::Int(*row_count as i64)),
Object::MatrixRowSlice(matrix_array, _) => {
match &**matrix_array {
Object::MatrixArray(_, col_count, _, _) => Ok(Value::Int(*col_count as i64)),
_ => Err(Error::Interp(String::from("invalid matrix array type"))),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function length"))),
}
},
Some(Value::Ref(object)) => {
let object_g = rw_lock_read(object)?;
match &*object_g {
MutObject::Array(elems) => Ok(Value::Int(elems.len() as i64)),
_ => Err(Error::Interp(String::from("unsupported type for function length"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function length"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn rows(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::Matrix(a) => Ok(Value::Int(a.row_count() as i64)),
Object::MatrixArray(row_count, _, _, _) => Ok(Value::Int(*row_count as i64)),
_ => Err(Error::Interp(String::from("unsupported type for function rows"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function rows"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn columns(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::Matrix(a) => Ok(Value::Int(a.col_count() as i64)),
Object::MatrixArray(_, col_count, _, _) => Ok(Value::Int(*col_count as i64)),
Object::MatrixRowSlice(matrix_array, _) => {
match &**matrix_array {
Object::MatrixArray(_, col_count, _, _) => Ok(Value::Int(*col_count as i64)),
_ => Err(Error::Interp(String::from("invalid matrix array type"))),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function columns"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function columns"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn get(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 2 || arg_values.len() > 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(Value::Object(object)), Some(i_value @ (Value::Int(_) | Value::Float(_))), None) => {
match &**object {
Object::String(s) => {
let i = i_value.to_i64();
if i < 1 || i > (s.chars().count() as i64) {
return Ok(Value::None);
}
match s.chars().nth((i - 1) as usize) {
Some(c) => {
let mut t = String::new();
t.push(c);
Ok(Value::Object(Arc::new(Object::String(t))))
}
None => Ok(Value::None),
}
},
Object::MatrixArray(row_count, _, _, _) => {
let i = i_value.to_i64();
if i < 1 || i > (*row_count as i64) {
return Ok(Value::None);
}
Ok(Value::Object(Arc::new(Object::MatrixRowSlice(object.clone(), (i - 1) as usize))))
},
Object::MatrixRowSlice(matrix_array, i) => {
let j = i_value.to_i64();
match &**matrix_array {
Object::MatrixArray(row_count, col_count, transpose_flag, xs) => {
if j < 1 || j > (*col_count as i64) {
return Ok(Value::None);
}
let k = match transpose_flag {
TransposeFlag::NoTranspose => i * (*col_count) + ((j - 1) as usize),
TransposeFlag::Transpose => ((j - 1) as usize) * (*row_count) + i,
};
Ok(xs.get(k).map(|x| Value::Float(*x)).unwrap_or(Value::None))
},
_ => Err(Error::Interp(String::from("invalid matrix array type"))),
}
},
_ => Err(Error::Interp(String::from("unsupported types for function get"))),
}
},
(Some(Value::Ref(object)), Some(i_value @ (Value::Int(_) | Value::Float(_) | Value::Object(_))), None) => {
let object_g = rw_lock_read(&**object)?;
match &*object_g {
MutObject::Array(elems) => {
match i_value {
Value::Int(_) | Value::Float(_) => {
let i = i_value.to_i64();
if i < 1 || i > (elems.len() as i64) {
return Ok(Value::None);
}
Ok(elems.get((i - 1) as usize).map(|x| x.clone()).unwrap_or(Value::None))
},
_ => Err(Error::Interp(String::from("unsupported types for function get"))),
}
},
MutObject::Struct(fields) => {
match i_value {
Value::Object(i_object) => {
match &**i_object {
Object::String(ident) => Ok(fields.get(ident).map(|x| x.clone()).unwrap_or(Value::None)),
_ => Err(Error::Interp(String::from("unsupported types for function get"))),
}
},
_ => Err(Error::Interp(String::from("unsupported types for function get"))),
}
},
}
},
(Some(Value::Object(object)), Some(i_value @ (Value::Int(_) | Value::Float(_))), Some(j_value @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::MatrixArray(row_count, col_count, transpose_flag, xs) => {
let i = i_value.to_i64();
let j = j_value.to_i64();
if i < 1 || i > (*row_count as i64) {
return Ok(Value::None);
}
if j < 1 || j > (*col_count as i64) {
return Ok(Value::None);
}
let k = match transpose_flag {
TransposeFlag::NoTranspose => ((i - 1) as usize) * (*col_count) + ((j - 1) as usize),
TransposeFlag::Transpose => ((j - 1) as usize) * (*row_count) + ((i - 1) as usize),
};
Ok(xs.get(k).map(|x| Value::Float(*x)).unwrap_or(Value::None))
},
_ => Err(Error::Interp(String::from("unsupported types for function get"))),
}
},
(Some(_), Some(_), _) => Err(Error::Interp(String::from("unsupported types for function get"))),
(_, _, _) => Err(Error::Interp(String::from("no argument")))
}
}
pub fn getdiag(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), Some(i_value @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::MatrixArray(row_count, col_count, _, xs) => {
if *row_count != *col_count {
return Err(Error::Interp(String::from("number of rows isn't equal to number of columns")));
}
let i = i_value.to_i64();
if i < 1 || i > (*row_count as i64) {
return Ok(Value::None);
}
let k = ((i - 1) as usize) * (*col_count) + ((i - 1) as usize);
Ok(xs.get(k).map(|x| Value::Float(*x)).unwrap_or(Value::None))
},
_ => Err(Error::Interp(String::from("unsupported type for function getdiag"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function getdiag"))),
(_, _) => Err(Error::Interp(String::from("no argument")))
}
}
pub fn split(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 || arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), None) => {
match &**object {
Object::String(s) => {
let ss = s.split_whitespace();
let elems: Vec<Value> = ss.map(|t| Value::Object(Arc::new(Object::String(String::from(t))))).collect();
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(elems)))))
},
_ => Err(Error::Interp(String::from("unsupported type for function split"))),
}
},
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::String(s), Object::String(t)) => {
let ss = s.split(t.as_str());
let elems: Vec<Value> = ss.map(|u| Value::Object(Arc::new(Object::String(String::from(u))))).collect();
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(elems)))))
},
(_, _) => Err(Error::Interp(String::from("unsupported types for function split"))),
}
},
(Some(_), None) => Err(Error::Interp(String::from("unsupported type for function split"))),
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function split"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn trim(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => Ok(Value::Object(Arc::new(Object::String(String::from(s.trim()))))),
_ => Err(Error::Interp(String::from("unsupported type for function trim"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function trim"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn contains(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::String(s), Object::String(t)) => Ok(Value::Bool(s.contains(t.as_str()))),
(_, _) => Err(Error::Interp(String::from("unsupported types for function contains"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function contains"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn startswith(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::String(s), Object::String(t)) => Ok(Value::Bool(s.starts_with(t.as_str()))),
(_, _) => Err(Error::Interp(String::from("unsupported types for function startswith"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function startswith"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn endswith(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::String(s), Object::String(t)) => Ok(Value::Bool(s.ends_with(t.as_str()))),
(_, _) => Err(Error::Interp(String::from("unsupported types for function endswith"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function endswith"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn replace(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(Value::Object(object)), Some(Value::Object(object2)), Some(Value::Object(object3))) => {
match (&**object, &**object2, &**object3) {
(Object::String(s), Object::String(t), Object::String(u)) => Ok(Value::Object(Arc::new(Object::String(s.replace(t.as_str(), u.as_str()))))),
(_, _, _) => Err(Error::Interp(String::from("unsupported types for function replace"))),
}
},
(Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function replace"))),
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn upper(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => Ok(Value::Object(Arc::new(Object::String(s.to_uppercase())))),
_ => Err(Error::Interp(String::from("unsupported type for function upper"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function upper"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn lower(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => Ok(Value::Object(Arc::new(Object::String(s.to_lowercase())))),
_ => Err(Error::Interp(String::from("unsupported type for function lower"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function lower"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
enum SortType
{
Bool,
Number,
String,
Incomparable,
}
pub fn sort(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Ref(object)) => {
let mut object_g = rw_lock_write(object)?;
match &mut *object_g {
MutObject::Array(elems) => {
let mut sort_type: Option<SortType> = None;
for elem in &*elems {
let new_sort_type = match elem {
Value::Bool(_) => SortType::Bool,
Value::Int(_) => SortType::Number,
Value::Float(n) => if !n.is_nan() { SortType::Number } else { SortType::Incomparable },
Value::Object(elem_object) => {
match &**elem_object {
Object::String(_) => SortType::String,
_ => SortType::Incomparable,
}
},
_ => SortType::Incomparable,
};
if sort_type.map(|t| t == new_sort_type).unwrap_or(true) {
sort_type = Some(new_sort_type);
} else {
return Err(Error::Interp(String::from("array has elements which can't be compared")));
}
}
match sort_type {
Some(SortType::Incomparable) => return Err(Error::Interp(String::from("array has incomparable elements"))),
_ => (),
}
elems.sort_by(|x, y| x.partial_cmp(y).unwrap());
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function sort"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function sort"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn reverse(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Ref(object)) => {
let mut object_g = rw_lock_write(object)?;
match &mut *object_g {
MutObject::Array(elems) => {
elems.reverse();
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function reverse"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function reverse"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn any(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(a_value), Some(data_value), Some(fun_value)) => {
match a_value.iter()? {
Some(mut iter) => {
loop {
match iter.next() {
Some(Ok(elem)) => {
if fun_value.apply(interp, env, &[data_value.clone(), elem])?.to_bool() {
return Ok(Value::Bool(true));
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(Value::Bool(false))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn all(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(a_value), Some(data_value), Some(fun_value)) => {
match a_value.iter()? {
Some(mut iter) => {
loop {
match iter.next() {
Some(Ok(elem)) => {
if !fun_value.apply(interp, env, &[data_value.clone(), elem])?.to_bool() {
return Ok(Value::Bool(false));
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(Value::Bool(true))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn find(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(a_value), Some(data_value), Some(fun_value)) => {
match a_value.iter()? {
Some(mut iter) => {
let mut i = 1i64;
loop {
match iter.next() {
Some(Ok(elem)) => {
if fun_value.apply(interp, env, &[data_value.clone(), elem])?.to_bool() {
return Ok(Value::Int(i));
}
match i.checked_add(1) {
Some(j) => i = j,
None => return Err(Error::Interp(String::from("too large index"))),
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(Value::None)
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn filter(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(a_value), Some(data_value), Some(fun_value)) => {
match a_value.iter()? {
Some(mut iter) => {
let mut i_values: Vec<Value> = Vec::new();
let mut i = 1i64;
loop {
match iter.next() {
Some(Ok(elem)) => {
if fun_value.apply(interp, env, &[data_value.clone(), elem])?.to_bool() {
i_values.push(Value::Int(i));
}
match i.checked_add(1) {
Some(j) => i = j,
None => return Err(Error::Interp(String::from("too large index"))),
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(i_values)))))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn max(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 || arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value), None) => {
match value.iter()? {
Some(mut iter) => {
let mut max_elem = Value::None;
loop {
match iter.next() {
Some(Ok(elem)) => {
match max_elem {
Value::None => max_elem = elem,
_ => {
if elem > max_elem {
max_elem = elem;
}
},
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(max_elem)
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
(Some(Value::Int(a)), Some(Value::Int(b))) => Ok(Value::Int((*a).max(*b))),
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => Ok(Value::Float(value.to_f32().max(value2.to_f32()))),
(Some(Value::Object(object)), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_max_for_scalar(a, value2.to_f32())?)))),
_ => Err(Error::Interp(String::from("unsupported types for function max"))),
}
},
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(Value::Object(object2))) => {
match &**object2 {
Object::Matrix(b) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_max_for_scalar(b, value.to_f32())?)))),
_ => Err(Error::Interp(String::from("unsupported types for function max"))),
}
},
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::Matrix(a), Object::Matrix(b)) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_max(a, b)?)))),
_ => Err(Error::Interp(String::from("unsupported types for function max"))),
}
},
(Some(value @ Value::Ref(_)), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => value.dot1("unsupported types for function max", |a| max(interp, env, &[a.clone(), value2.clone()])),
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ Value::Ref(_))) => value2.dot1("unsupported types for function max", |b| max(interp, env, &[value.clone(), b.clone()])),
(Some(value), Some(value2)) => value.dot2(value2, "unsupported types for function max", |a, b| max(interp, env, &[a.clone(), b.clone()])),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn min(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 || arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value), None) => {
match value.iter()? {
Some(mut iter) => {
let mut min_elem = Value::None;
loop {
match iter.next() {
Some(Ok(elem)) => {
match min_elem {
Value::None => min_elem = elem,
_ => {
if elem < min_elem {
min_elem = elem;
}
},
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(min_elem)
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
(Some(Value::Int(a)), Some(Value::Int(b))) => Ok(Value::Int((*a).min(*b))),
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => Ok(Value::Float(value.to_f32().min(value2.to_f32()))),
(Some(Value::Object(object)), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_min_for_scalar(a, value2.to_f32())?)))),
_ => Err(Error::Interp(String::from("unsupported types for function min"))),
}
},
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(Value::Object(object2))) => {
match &**object2 {
Object::Matrix(b) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_min_for_scalar(b, value.to_f32())?)))),
_ => Err(Error::Interp(String::from("unsupported types for function min"))),
}
},
(Some(Value::Object(object)), Some(Value::Object(object2))) => {
match (&**object, &**object2) {
(Object::Matrix(a), Object::Matrix(b)) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_min(a, b)?)))),
_ => Err(Error::Interp(String::from("unsupported types for function min"))),
}
},
(Some(value @ Value::Ref(_)), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => value.dot1("unsupported types for function min", |a| min(interp, env, &[a.clone(), value2.clone()])),
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ Value::Ref(_))) => value2.dot1("unsupported types for function min", |b| min(interp, env, &[value.clone(), b.clone()])),
(Some(value), Some(value2)) => value.dot2(value2, "unsupported types for function min", |a, b| min(interp, env, &[a.clone(), b.clone()])),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn imax(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value) => {
match value.iter()? {
Some(mut iter) => {
let mut max_elem = Value::None;
let mut i: Option<i64> = None;
let mut j = 1i64;
loop {
match iter.next() {
Some(Ok(elem)) => {
match max_elem {
Value::None => {
max_elem = elem;
i = Some(j);
},
_ => {
if elem > max_elem {
max_elem = elem;
i = Some(j);
}
},
}
match j.checked_add(1) {
Some(k) => j = k,
None => return Err(Error::Interp(String::from("too large index"))),
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(i.map(|i| Value::Int(i)).unwrap_or(Value::None))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn imin(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value) => {
match value.iter()? {
Some(mut iter) => {
let mut min_elem = Value::None;
let mut i: Option<i64> = None;
let mut j = 1i64;
loop {
match iter.next() {
Some(Ok(elem)) => {
match min_elem {
Value::None => {
min_elem = elem;
i = Some(j);
},
_ => {
if elem < min_elem {
min_elem = elem;
i = Some(j);
}
},
}
match j.checked_add(1) {
Some(k) => j = k,
None => return Err(Error::Interp(String::from("too large index"))),
}
},
Some(Err(err)) => return Err(err),
None => break,
}
}
Ok(i.map(|i| Value::Int(i)).unwrap_or(Value::None))
},
None => Err(Error::Interp(String::from("value isn't iterable"))),
}
},
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn push(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Ref(a_object)), Some(value)) => {
let mut a_object_g = rw_lock_write(a_object)?;
match &mut *a_object_g {
MutObject::Array(elems) => {
elems.push(value.clone());
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported types for function push"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function push"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn pop(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Ref(a_object)) => {
let mut a_object_g = rw_lock_write(a_object)?;
match &mut *a_object_g {
MutObject::Array(elems) => {
match elems.pop() {
Some(value) => Ok(value),
None => Ok(Value::None),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function pop"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function pop"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn append(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Ref(a_object)), Some(Value::Ref(b_object))) => {
if !Arc::ptr_eq(a_object, b_object) {
let mut a_object_g = rw_lock_write(a_object)?;
let b_object_g = rw_lock_read(b_object)?;
match (&mut *a_object_g, &*b_object_g) {
(MutObject::Array(elems), MutObject::Array(elems2)) => {
elems.extend_from_slice(elems2.as_slice());
Ok(Value::None)
},
(MutObject::Struct(fields), MutObject::Struct(fields2)) => {
for (ident2, field2) in fields2 {
fields.insert(ident2.clone(), field2.clone());
}
Ok(Value::None)
},
(_, _) => Err(Error::Interp(String::from("unsupported types for function append"))),
}
} else {
let mut a_object_g = rw_lock_write(a_object)?;
match &mut *a_object_g {
MutObject::Array(elems) => {
let elems2 = elems.clone();
elems.extend_from_slice(elems2.as_slice());
Ok(Value::None)
},
MutObject::Struct(_) => Ok(Value::None),
}
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function append"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn insert(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(Value::Ref(a_object)), Some(i_value @ (Value::Int(_) | Value::Float(_) | Value::Object(_))), Some(value)) => {
let mut a_object_g = rw_lock_write(a_object)?;
match &mut *a_object_g {
MutObject::Array(elems) => {
match i_value {
Value::Int(_) | Value::Float(_) => {
let i = i_value.to_i64();
if i < 1 || i > (elems.len() as i64).saturating_add(1) {
return Err(Error::Interp(String::from("index out of bounds")));
}
elems.insert((i - 1) as usize, value.clone());
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported types for function insert"))),
}
},
MutObject::Struct(fields) => {
match i_value {
Value::Object(i_object) => {
match &**i_object {
Object::String(ident) => Ok(fields.insert(ident.clone(), value.clone()).unwrap_or(Value::None)),
_ => Err(Error::Interp(String::from("unsupported types for function insert"))),
}
},
_ => Err(Error::Interp(String::from("unsupported types for function insert"))),
}
},
}
},
(Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function insert"))),
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn remove(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Ref(a_object)), Some(i_value @ (Value::Int(_) | Value::Float(_) | Value::Object(_)))) => {
let mut a_object_g = rw_lock_write(a_object)?;
match &mut *a_object_g {
MutObject::Array(elems) => {
match i_value {
Value::Int(_) | Value::Float(_) => {
let i = i_value.to_i64();
if i < 1 || i > (elems.len() as i64) {
return Ok(Value::None);
}
Ok(elems.remove((i - 1) as usize))
},
_ => Err(Error::Interp(String::from("unsupported types for function remove"))),
}
},
MutObject::Struct(fields) => {
match i_value {
Value::Object(i_object) => {
match &**i_object {
Object::String(ident) => Ok(fields.remove(ident).unwrap_or(Value::None)),
_ => Err(Error::Interp(String::from("unsupported types for function remove"))),
}
},
_ => Err(Error::Interp(String::from("unsupported types for function remove"))),
}
},
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function remove"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn errorkind(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::Error(kind, _) => Ok(Value::Object(Arc::new(Object::String(kind.clone())))),
_ => Err(Error::Interp(String::from("unsupported type for function errorkind"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function errorkind"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn errormsg(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::Error(_, msg) => Ok(Value::Object(Arc::new(Object::String(msg.clone())))),
_ => Err(Error::Interp(String::from("unsupported type for function errormsg"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function errormsg"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn isequal(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2(arg_values, |a, b| Ok(Value::Bool(a.eq_without_types(b)?))) }
pub fn isnotequal(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2(arg_values, |a, b| Ok(Value::Bool(!a.eq_without_types(b)?))) }
pub fn isless(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2(arg_values, |a, b| Ok(Value::Bool(a < b))) }
pub fn isgreaterequal(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2(arg_values, |a, b| Ok(Value::Bool(a >= b))) }
pub fn isgreater(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2(arg_values, |a, b| Ok(Value::Bool(a > b))) }
pub fn islessequal(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2(arg_values, |a, b| Ok(Value::Bool(a <= b))) }
pub fn sigmoid(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function sigmoid", |a| 1.0 / (1.0 + (-a).exp()), matrix_sigmoid) }
pub fn tanh(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function tanh", f32::tanh, matrix_tanh) }
pub fn swish(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function swish", |a| a / (1.0 + (-a).exp()), matrix_swish) }
pub fn softmax(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value @ (Value::Int(_) | Value::Float(_))) => Ok(Value::Float(value.to_f32().exp() / value.to_f32().exp())),
Some(Value::Object(object)) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_softmax(a)?)))),
_ => Err(Error::Interp(String::from("unsupported type for function softmax"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function softmax"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn sqrt(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function sqrt", f32::sqrt, matrix_sqrt) }
pub fn reallytranspose(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value @ (Value::Int(_) | Value::Float(_))) => Ok(value.clone()),
Some(Value::Object(object)) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_really_transpose(a)?)))),
_ => Err(Error::Interp(String::from("unsupported type for function reallytranspose"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function reallytranspose"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn repeat(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), Some(n_value @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::Matrix(a) => {
let n = n_value.to_i64();
let (m, l) = if a.col_count() == 1 {
(a.row_count() as i64, n)
} else if a.row_count() == 1 {
(n, a.col_count() as i64)
} else {
return Err(Error::Interp(String::from("number of columns or rows isn't one")));
};
checked_mul_row_count_and_col_count(m, l)?;
match matrix_repeat(a, n as usize)? {
Some(b) => Ok(Value::Object(Arc::new(Object::Matrix(b)))),
None => return Err(Error::Interp(String::from("number of columns or rows isn't one"))),
}
},
_ => Err(Error::Interp(String::from("unsupported types for function repeat"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function repeat"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn modulo(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Int(a)), Some(Value::Int(b))) => {
match a.checked_rem(*b) {
Some(c) => Ok(Value::Int(c)),
None => {
if *b == 0 {
Err(Error::Interp(String::from("division by zero")))
} else {
Err(Error::Interp(String::from("overflow in function mod")))
}
},
}
},
(Some(value @ (Value::Int(_) | Value::Float(_))), Some(value2 @ (Value::Int(_) | Value::Float(_)))) => Ok(Value::Float(value.to_f32() % value2.to_f32())),
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function mod"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn abs(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Int(a)) => Ok(Value::Int(a.abs())),
Some(Value::Float(a)) => Ok(Value::Float(a.abs())),
Some(Value::Object(object)) => {
match &**object {
Object::Matrix(a) => Ok(Value::Object(Arc::new(Object::Matrix(matrix_abs(a)?)))),
_ => Err(Error::Interp(String::from("unsupported type for function abs"))),
}
},
Some(value) => value.dot1("unsupported type for function abs", |a| abs(interp, env, &[a.clone()])),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn pow(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2_for_f32_and_matrix(arg_values, "unsupported types for function pow", f32::powf, matrix_pow_for_scalar, matrix_rpow_for_scalar, matrix_pow) }
pub fn exp(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function exp", f32::exp, matrix_exp) }
pub fn log(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function log", f32::ln, matrix_ln) }
pub fn log2(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function log2", f32::log2, matrix_log2) }
pub fn log10(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function log10", f32::log10, matrix_log10) }
pub fn sin(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function sin", f32::sin, matrix_sin) }
pub fn cos(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function cos", f32::cos, matrix_cos) }
pub fn tan(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function tan", f32::tan, matrix_tan) }
pub fn asin(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function asin", f32::asin, matrix_asin) }
pub fn acos(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function acos", f32::acos, matrix_acos) }
pub fn atan(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function atan", f32::atan, matrix_atan) }
pub fn atan2(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun2_for_f32_and_matrix(arg_values, "unsupported types for function atan2", f32::atan2, matrix_atan2_for_scalar, matrix_ratan2_for_scalar, matrix_atan2) }
pub fn sinh(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function sinh", f32::sinh, matrix_sinh) }
pub fn cosh(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function cosh", f32::cosh, matrix_cosh) }
pub fn asinh(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function asinh", f32::asinh, matrix_asinh) }
pub fn acosh(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function acosh", f32::acosh, matrix_acosh) }
pub fn atanh(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function atanh", f32::atanh, matrix_atanh) }
pub fn sign(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function sign", f32::signum, matrix_signum) }
pub fn ceil(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function ceil", f32::ceil, matrix_ceil) }
pub fn floor(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function floor", f32::floor, matrix_floor) }
pub fn round(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function round", f32::round, matrix_round) }
pub fn trunc(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{ fun1_for_f32_and_matrix(arg_values, "unsupported type for function trunc", f32::trunc, matrix_trunc) }
pub fn rand(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
Ok(Value::Float(random()))
}
pub fn randi(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 || arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(max_value @ (Value::Int(_) | Value::Float(_))), None) => {
let max = max_value.to_i64();
Ok(Value::Int(random_range(1..=max)))
}
(Some(min_value @ (Value::Int(_) | Value::Float(_))), Some(max_value @ (Value::Int(_) | Value::Float(_)))) => {
let min = min_value.to_i64();
let max = max_value.to_i64();
Ok(Value::Int(random_range(min..=max)))
},
(Some(_), None) => Err(Error::Interp(String::from("unsupported type for function randi"))),
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function randi"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn str2int(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => {
match s.parse::<i64>() {
Ok(n) => Ok(Value::Int(n)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("parseint"), format!("{}", err))))),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function str2int"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function str2int"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn str2float(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => {
match s.parse::<f32>() {
Ok(n) => Ok(Value::Float(n)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("parsefloat"), format!("{}", err))))),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function str2float"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function str2float"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn hex2dec(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => {
let s2 = if s.starts_with("0X") || s.starts_with("0x") {
&s[2..]
} else {
s
};
match i64::from_str_radix(s2, 16) {
Ok(n) => Ok(Value::Int(n)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("parseint"), format!("{}", err))))),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function hex2dec"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function hex2dec"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn char2code(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => {
match s.chars().next() {
Some(c) => Ok(Value::Int((c as u32) as i64)),
None => Ok(Value::None),
}
},
_ => Err(Error::Interp(String::from("unsupported type for function char2code"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function char2code"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn code2char(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value @ (Value::Int(_) | Value::Float(_))) => {
let n = value.to_i64();
if n < 0 || n > (u32::MAX as i64) {
return Ok(Value::None);
}
match char::from_u32(n as u32) {
Some(c) => {
let mut s = String::new();
s.push(c);
Ok(Value::Object(Arc::new(Object::String(s))))
},
None => Ok(Value::None),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function code2char"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn formatmillis(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(Value::Object(object)), Some(millis_value @ (Value::Int(_) | Value::Float(_)))) => {
match &**object {
Object::String(s) => {
let millis = millis_value.to_i64();
let secs = millis / 1000;
if s == &String::from("s") {
Ok(Value::Object(Arc::new(Object::String(format!("{}.{:03}s", secs, millis % 1000)))))
} else if s == &String::from("ms") {
Ok(Value::Object(Arc::new(Object::String(format!("{}m{}.{:03}s", secs / 60, secs % 60, millis % 1000)))))
} else if s == &String::from("hms") {
Ok(Value::Object(Arc::new(Object::String(format!("{}h{}m{}.{:03}s", (secs / 60) / 60, (secs / 60) % 60, secs % 60, millis % 1000)))))
} else {
Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("invalid format")))))
}
},
_ => Err(Error::Interp(String::from("unsupported types for function formatmillis"))),
}
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function formatmillis"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn withwidth(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 2 || arg_values.len() > 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(value), Some(width_value @ (Value::Int(_) | Value::Float(_))), None) => {
let width = width_value.to_i64();
if width < 0 {
return Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("width is negative")))));
}
if width > (isize::MAX as i64) {
return Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("too large width")))));
}
Ok(Value::Object(Arc::new(Object::String(format!("{:width$}", format!("{}", value), width = width as usize)))))
},
(Some(value), Some(width_value @ (Value::Int(_) | Value::Float(_))), Some(Value::Object(align_object))) => {
match &**align_object {
Object::String(align) => {
let width = width_value.to_i64();
if width < 0 {
return Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("width is negative")))));
}
if width > (isize::MAX as i64) {
return Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("too large width")))));
}
if align == &String::from("left") || align == &String::from("l") {
Ok(Value::Object(Arc::new(Object::String(format!("{:<width$}", format!("{}", value), width = width as usize)))))
} else if align == &String::from("center") || align == &String::from("c") {
Ok(Value::Object(Arc::new(Object::String(format!("{:^width$}", format!("{}", value), width = width as usize)))))
} else if align == &String::from("right") || align == &String::from("r") {
Ok(Value::Object(Arc::new(Object::String(format!("{:>width$}", format!("{}", value), width = width as usize)))))
} else {
Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("invalid alignment")))))
}
},
_ => Err(Error::Interp(String::from("unsupported types for function withwidth"))),
}
},
(Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function withwidth"))),
(_, _, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn withzeros(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value), Some(width_value @ (Value::Int(_) | Value::Float(_)))) => {
let width = width_value.to_i64();
if width < 0 {
return Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("width is negative")))));
}
if width > (isize::MAX as i64) {
return Ok(Value::Object(Arc::new(Object::Error(String::from("format"), String::from("too large width")))));
}
Ok(Value::Object(Arc::new(Object::String(format!("{:0>width$}", format!("{}", value), width = width as usize)))))
},
(Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for function withzeros"))),
(_, _) => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn readline(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match env.stdin() {
Input::Std => {
let mut line = String::new();
match stdin().read_line(&mut line) {
Ok(_) => Ok(Value::Object(Arc::new(Object::String(line)))),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Input::Null => Ok(Value::Object(Arc::new(Object::String(String::new())))),
}
}
pub fn format(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
let mut s = String::new();
for arg_value in arg_values {
s.push_str(format!("{}", arg_value).as_str());
}
Ok(Value::Object(Arc::new(Object::String(s))))
}
pub fn print(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
match env.stdout() {
Output::Std => {
for arg_value in arg_values {
print!("{}", arg_value);
}
},
Output::Null => (),
Output::Cursor(cursor) => {
let mut cursor_g = rw_lock_write(cursor)?;
for arg_value in arg_values {
write!(&mut *cursor_g, "{}", arg_value).unwrap();
}
},
}
Ok(Value::None)
}
pub fn println(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
match env.stdout() {
Output::Std => {
for arg_value in arg_values {
print!("{}", arg_value);
}
println!("");
},
Output::Null => (),
Output::Cursor(cursor) => {
let mut cursor_g = rw_lock_write(cursor)?;
for arg_value in arg_values {
write!(&mut *cursor_g, "{}", arg_value).unwrap();
}
writeln!(&mut *cursor_g, "").unwrap();
},
}
Ok(Value::None)
}
pub fn eprint(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
match env.stderr() {
Output::Std => {
for arg_value in arg_values {
eprint!("{}", arg_value);
}
},
Output::Null => (),
Output::Cursor(cursor) => {
let mut cursor_g = rw_lock_write(cursor)?;
for arg_value in arg_values {
write!(&mut *cursor_g, "{}", arg_value).unwrap();
}
},
}
Ok(Value::None)
}
pub fn eprintln(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
match env.stderr() {
Output::Std => {
for arg_value in arg_values {
eprint!("{}", arg_value);
}
eprintln!("");
},
Output::Null => (),
Output::Cursor(cursor) => {
let mut cursor_g = rw_lock_write(cursor)?;
for arg_value in arg_values {
write!(&mut *cursor_g, "{}", arg_value).unwrap();
}
writeln!(&mut *cursor_g, "").unwrap();
},
}
Ok(Value::None)
}
pub fn flush(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match env.stdout() {
Output::Std => {
match stdout().flush() {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
_ => Ok(Value::Bool(true)),
}
}
pub fn eflush(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match env.stderr() {
Output::Std => {
match stderr().flush() {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
_ => Ok(Value::Bool(true)),
}
}
pub fn cd(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let new_dir_name = get_first_arg_string(arg_values, "unsupported type for function cd")?;
let old_dir_name = match std::env::current_dir() {
Ok(path) => path.to_string_lossy().into_owned(),
Err(err) => return Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
};
match std::env::set_current_dir(new_dir_name) {
Ok(()) => Ok(Value::Object(Arc::new(Object::String(old_dir_name)))),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn pwd(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match std::env::current_dir() {
Ok(path) => Ok(Value::Object(Arc::new(Object::String(path.to_string_lossy().into_owned())))),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn exist(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function exist")?;
match fs::metadata(file_name.as_str()) {
Ok(_) => Ok(Value::Bool(true)),
Err(err) if err.kind() == ErrorKind::NotFound => Ok(Value::Bool(false)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn filetype(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function filetype")?;
match fs::metadata(file_name.as_str()) {
Ok(metadata) => {
if metadata.is_dir() {
Ok(Value::Object(Arc::new(Object::String(String::from("dir")))))
} else {
Ok(Value::Object(Arc::new(Object::String(String::from("file")))))
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn dir(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let dir_name = get_first_arg_string(arg_values, "unsupported type for function dir")?;
match read_dir(dir_name.as_str()) {
Ok(entries) => {
let mut name_values: Vec<Value> = Vec::new();
for entry in entries {
match entry {
Ok(entry) => name_values.push(Value::Object(Arc::new(Object::String(entry.file_name().to_string_lossy().into_owned())))),
Err(err) => return Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(name_values)))))
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn mkdir(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let dir_name = get_first_arg_string(arg_values, "unsupported type for function mkdir")?;
match create_dir(dir_name.as_str()) {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn rmdir(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let dir_name = get_first_arg_string(arg_values, "unsupported type for function rmdir")?;
match remove_dir(dir_name.as_str()) {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn rmfile(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function rmfile")?;
match remove_file(file_name.as_str()) {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn copy(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let (src_file_name, dst_file_name) = match (arg_values.get(0), arg_values.get(1)) {
(Some(src_file_name_value), Some(dst_file_name_value)) => {
match (src_file_name_value.to_opt_string(), dst_file_name_value.to_opt_string()) {
(Some(tmp_src_file_name), Some(tmp_dst_file_name)) => (tmp_src_file_name, tmp_dst_file_name),
(_, _) => return Err(Error::Interp(String::from("unsupported types for function copy"))),
}
},
(_, _) => return Err(Error::Interp(String::from("no argument"))),
};
match fs::copy(src_file_name.as_str(), dst_file_name.as_str()) {
Ok(_) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn rename(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let (src_file_name, dst_file_name) = match (arg_values.get(0), arg_values.get(1)) {
(Some(src_file_name_value), Some(dst_file_name_value)) => {
match (src_file_name_value.to_opt_string(), dst_file_name_value.to_opt_string()) {
(Some(tmp_src_file_name), Some(tmp_dst_file_name)) => (tmp_src_file_name, tmp_dst_file_name),
(_, _) => return Err(Error::Interp(String::from("unsupported types for function rename"))),
}
},
(_, _) => return Err(Error::Interp(String::from("no argument"))),
};
match fs::rename(src_file_name.as_str(), dst_file_name.as_str()) {
Ok(_) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn spawn(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let cmd_name = get_first_arg_string(arg_values, "unsupported type for function spawn")?;
let mut cmd_args: Vec<String> = Vec::new();
for arg_value in &arg_values[1..] {
cmd_args.push(format!("{}", arg_value));
}
match Command::new(cmd_name).args(cmd_args).spawn() {
Ok(mut child) => {
match child.wait() {
Ok(exit_status) => {
match exit_status.code() {
Some(code) => Ok(Value::Int(code as i64)),
None => Ok(Value::Object(Arc::new(Object::Error(String::from("exitstatus"), String::from("process terminated by signal"))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn exit(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(value @ (Value::Int(_) | Value::Float(_))) => Err(Error::Stop(Stop::Exit(value.to_i64() as i32))),
Some(_) => Err(Error::Interp(String::from("unsupported type for fuction exit"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn load(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function load")?;
match load_values(file_name.as_str(), env) {
Ok(values) => Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(values))))),
Err(Error::Io(err)) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
Err(err) => Err(err),
}
}
pub fn save(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function save")?;
match save_values(file_name.as_str(), &arg_values[1..]) {
Ok(()) => Ok(Value::Bool(true)),
Err(Error::Io(err)) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
Err(err) => Err(err),
}
}
pub fn loadstr(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function loadstr")?;
match File::open(file_name.as_str()) {
Ok(mut file) => {
let mut s = String::new();
match file.read_to_string(&mut s) {
Ok(_) => Ok(Value::Object(Arc::new(Object::String(s)))),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn savestr(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let (file_name, str_value) = match (arg_values.get(0), arg_values.get(1)) {
(Some(file_name_value), Some(str_value)) => {
match file_name_value.to_opt_string() {
Some(tmp_file_name) => (tmp_file_name, str_value.clone()),
None => return Err(Error::Interp(String::from("unsupported type for function savestr"))),
}
},
(_, _) => return Err(Error::Interp(String::from("no argument"))),
};
match File::create(file_name.as_str()) {
Ok(file) => {
let mut w = BufWriter::new(file);
match write!(&mut w, "{}", str_value) {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn loadtoml(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function loadtoml")?;
match File::open(file_name.as_str()) {
Ok(mut file) => {
let mut s = String::new();
match file.read_to_string(&mut s) {
Ok(_) => {
match toml::from_str(s.as_str()) {
Ok(value) => Ok(value),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("toml"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn savetoml(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let (file_name, value) = match (arg_values.get(0), arg_values.get(1)) {
(Some(file_name_value), Some(value)) => {
match file_name_value.to_opt_string() {
Some(tmp_file_name) => (tmp_file_name, value),
None => return Err(Error::Interp(String::from("unsupported type for function savetoml"))),
}
},
(_, _) => return Err(Error::Interp(String::from("no argument"))),
};
match toml::to_string(&value) {
Ok(s) => {
match File::create(file_name.as_str()) {
Ok(file) => {
let mut w = BufWriter::new(file);
match write!(&mut w, "{}", s) {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("toml"), format!("{}", err))))),
}
}
pub fn loadjson(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let file_name = get_first_arg_string(arg_values, "unsupported type for function loadjson")?;
match File::open(file_name.as_str()) {
Ok(mut file) => {
let mut s = String::new();
match file.read_to_string(&mut s) {
Ok(_) => {
match serde_json::from_str(s.as_str()) {
Ok(value) => Ok(value),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("json"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
}
pub fn savejson(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let (file_name, value) = match (arg_values.get(0), arg_values.get(1)) {
(Some(file_name_value), Some(value)) => {
match file_name_value.to_opt_string() {
Some(tmp_file_name) => (tmp_file_name, value),
None => return Err(Error::Interp(String::from("unsupported type for function savejson"))),
}
},
(_, _) => return Err(Error::Interp(String::from("no argument"))),
};
match serde_json::to_string(&value) {
Ok(s) => {
match File::create(file_name.as_str()) {
Ok(file) => {
let mut w = BufWriter::new(file);
match write!(&mut w, "{}", s) {
Ok(()) => Ok(Value::Bool(true)),
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("io"), format!("{}", err))))),
}
},
Err(err) => Ok(Value::Object(Arc::new(Object::Error(String::from("json"), format!("{}", err))))),
}
}
pub fn args(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let shared_env_g = rw_lock_read(env.shared_env())?;
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(shared_env_g.args().iter().map(|s| Value::Object(Arc::new(Object::String(s.clone())))).collect())))))
}
pub fn env(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
Ok(Value::Ref(Arc::new(RwLock::new(MutObject::Array(std::env::vars_os().map(|p| Value::Object(Arc::new(Object::String(format!("{}={}", p.0.to_string_lossy().into_owned(), p.1.to_string_lossy().into_owned()))))).collect())))))
}
pub fn scriptdir(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
Ok(Value::Object(Arc::new(Object::String(env.script_dir().to_string_lossy().into_owned()))))
}
pub fn libpath(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let shared_env_g = rw_lock_read(env.shared_env())?;
Ok(Value::Object(Arc::new(Object::String(shared_env_g.lib_path().to_string_lossy().into_owned()))))
}
pub fn domain(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match env.domain() {
Some(domain) => Ok(Value::Object(Arc::new(Object::String(String::from(domain))))),
None => Ok(Value::None),
}
}
fn name_with_domain(name: &str, env: &Env) -> Result<String>
{
if name.contains('/') {
Ok(String::from(name))
} else {
match env.domain() {
Some(domain) => {
let mut new_name = String::from(domain);
new_name.push('/');
new_name.push_str(name);
Ok(new_name)
},
None => Err(Error::Interp(String::from("name library without domain"))),
}
}
}
fn domain_from_name(name: &str) -> Result<String>
{
match name.split_once('/') {
Some((domain, _)) => Ok(String::from(domain)),
None => Err(Error::Interp(String::from("name library without domain"))),
}
}
fn use_lib(interp: &mut Interp, env: &mut Env, lib_name: &str) -> Result<()>
{
let domain = domain_from_name(lib_name)?;
let lib_path = {
let shared_env_g = rw_lock_read(env.shared_env())?;
OsString::from(shared_env_g.lib_path())
};
let mut res: Result<()> = Ok(());
for dir in std::env::split_paths(lib_path.as_os_str()) {
let mut script_dir = dir.clone();
script_dir.push(lib_name.replace('/', path::MAIN_SEPARATOR_STR));
let mut path = script_dir.clone();
path.push("lib.un");
match parse(path) {
Ok(tree) => {
let mut new_env = Env::new_with_script_dir_and_domain_and_shared_env(env.root_mod().clone(), script_dir.clone(), Some(domain), env.shared_env().clone());
new_env.set_stdin(*env.stdin());
new_env.set_stdout(env.stdout().clone());
new_env.set_stderr(env.stderr().clone());
interp.interpret(&mut new_env, &tree)?;
{
let mut shared_env_g = rw_lock_write(env.shared_env())?;
shared_env_g.add_used_lib(String::from(lib_name));
}
return Ok(());
},
Err(Error::ParserIo(path, err)) if err.kind() == ErrorKind::NotFound => res = Err(Error::ParserIo(path, err)),
Err(err) => return Err(err),
}
}
res
}
pub fn uselib(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let lib_name = get_first_arg_string(arg_values, "unsupported type for function uselib")?;
let lib_name = name_with_domain(lib_name.as_str(), env)?;
let is_used_lib = {
let shared_env_g = rw_lock_read(env.shared_env())?;
shared_env_g.has_used_lib(&lib_name)
};
if !is_used_lib {
use_lib(interp, env, lib_name.as_str())?;
}
Ok(Value::None)
}
pub fn reuselib(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let lib_name = get_first_arg_string(arg_values, "unsupported type for function reuselib")?;
let lib_name = name_with_domain(lib_name.as_str(), env)?;
use_lib(interp, env, lib_name.as_str())?;
Ok(Value::None)
}
pub fn run(interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let script_name = get_first_arg_string(arg_values, "unsupported type for function run")?;
let mut path_buf = PathBuf::from(env.script_dir());
path_buf.push(script_name.replace('/', path::MAIN_SEPARATOR_STR).as_str());
let tree = parse(path_buf)?;
let mut new_env = env.clone_without_stack();
interp.interpret(&mut new_env, &tree)?;
Ok(Value::None)
}
pub fn clock(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let shared_env_g = rw_lock_read(env.shared_env())?;
Ok(Value::Int(shared_env_g.instant().elapsed().as_millis() as i64))
}
fn mod_pair_for_name(env: &Env, name: &str, is_var: bool) -> Result<(Arc<RwLock<ModNode<Value, ()>>>, Vec<String>)>
{
let name_without_first_colons = if name.starts_with("::") {
&name[2..]
} else {
name
};
let idents: Vec<String> = name_without_first_colons.split("::").map(String::from).collect();
let end = if is_var {
idents.len().saturating_sub(1)
} else {
idents.len()
};
match idents.first() {
Some(ident) if ident == &String::from("root") => {
match ModNode::mod_from(env.root_mod(), &idents[1..cmp::max(end, 1)], false)? {
Some(mod1) => Ok((mod1, (&idents[1..]).to_vec())),
None => Err(Error::Interp(String::from("undefined module"))),
}
},
_ => {
match ModNode::mod_from(env.current_mod(), &idents[0..end], true)? {
Some(mod1) => Ok((mod1, idents)),
None => {
match ModNode::mod_from(env.root_mod(), &idents[0..end], false)? {
Some(mod1) => Ok((mod1, idents)),
None => Err(Error::Interp(String::from("undefined module"))),
}
},
}
},
}
}
pub fn usemod(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 || arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(name) => {
let (used_mod, idents) = mod_pair_for_name(env, name, false)?;
let ident = match arg_values.get(1) {
Some(Value::Object(object)) => {
match &**object {
Object::String(tmp_ident) => tmp_ident.clone(),
_ => return Err(Error::Interp(String::from("unsupported types for function usemod"))),
}
},
Some(_) => return Err(Error::Interp(String::from("unsupported types for function usemod"))),
None => {
match idents.last() {
Some(tmp_ident) => tmp_ident.clone(),
None => return Err(Error::Interp(String::from("no last identifier"))),
}
},
};
ModNode::add_used_mod(env.current_mod(), ident, used_mod)?;
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported types for function usemod"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported types for function usemod"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn usemods(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(name) => {
let mod1 = mod_pair_for_name(env, name, false)?.0;
let used_mods: Vec<(String, Arc<RwLock<ModNode<Value, ()>>>)> = {
let mod_g = rw_lock_read(&mod1)?;
mod_g.mods().iter().map(|p| (p.0.clone(), p.1.clone())).collect()
};
for (ident, used_mod) in &used_mods {
ModNode::add_used_mod(env.current_mod(), ident.clone(), used_mod.clone())?;
}
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function usemods"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function usemods"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn usevar(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 || arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(name) => {
let (used_var_mod, idents) = mod_pair_for_name(env, name, true)?;
let (ident, used_var_ident) = match arg_values.get(1) {
Some(Value::Object(object)) => {
match &**object {
Object::String(tmp_ident) => {
match idents.last() {
Some(tmp_used_var_ident) => (tmp_ident.clone(), tmp_used_var_ident.clone()),
None => return Err(Error::Interp(String::from("no last identifier"))),
}
},
_ => return Err(Error::Interp(String::from("unsupported types for function usevar"))),
}
},
Some(_) => return Err(Error::Interp(String::from("unsupported types for function usevar"))),
None => {
match idents.last() {
Some(tmp_used_var_ident) => (tmp_used_var_ident.clone(), tmp_used_var_ident.clone()),
None => return Err(Error::Interp(String::from("no last identifier"))),
}
},
};
{
let used_var_mod_g = rw_lock_read(&used_var_mod)?;
if !used_var_mod_g.has_var(&used_var_ident) {
return Err(Error::Interp(String::from("undefined variable")));
}
}
ModNode::add_used_var(env.current_mod(), ident.clone(), used_var_mod, used_var_ident)?;
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported types for function usevar"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported types for function usevar"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn usevars(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(name) => {
let used_var_mod = mod_pair_for_name(env, name, false)?.0;
let used_var_idents: Vec<String> = {
let used_var_mod_g = rw_lock_read(&used_var_mod)?;
used_var_mod_g.vars().keys().map(|s| s.clone()).collect()
};
for used_var_ident in &used_var_idents {
ModNode::add_used_var(env.current_mod(), used_var_ident.clone(), used_var_mod.clone(), used_var_ident.clone())?;
}
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function usevars"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function usevars"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn removeusemod(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(ident) => {
let mut current_mod_g = rw_lock_write(env.current_mod())?;
current_mod_g.remove_used_mod(ident);
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function removeusemod"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function removeusemod"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn removeusevar(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(ident) => {
let mut current_mod_g = rw_lock_write(env.current_mod())?;
current_mod_g.remove_used_var(ident);
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function removeusevar"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function removeusevar"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn removemod(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(ident) => {
let mut current_mod_g = rw_lock_write(env.current_mod())?;
current_mod_g.remove_mod(ident)?;
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function removemod"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function removemod"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn removevar(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(ident) => {
let mut current_mod_g = rw_lock_write(env.current_mod())?;
current_mod_g.remove_var(ident);
Ok(Value::None)
},
_ => Err(Error::Interp(String::from("unsupported type for function removevar"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function removevar"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn removelocalvar(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(ident) => Ok(Value::Bool(env.remove_local_var(ident))),
_ => Err(Error::Interp(String::from("unsupported type for function removelocalvar"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function removelocalvar"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn checkintr(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let intr_checker = {
let shared_env_g = rw_lock_read(env.shared_env())?;
shared_env_g.intr_checker().clone()
};
intr_checker.check()?;
Ok(Value::None)
}
pub fn backend(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
Ok(Value::Object(Arc::new(Object::String(String::from(matrix_backend_name()?)))))
}
pub fn version(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
Ok(Value::Object(Arc::new(Object::String(String::from(env!("CARGO_PKG_VERSION"))))))
}
pub fn reqver(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Object(object)) => {
match &**object {
Object::String(s) => {
let version = Version::parse(env!("CARGO_PKG_VERSION"))?;
let version_req = VersionReq::parse(s.as_str())?;
if version_req.matches(&version) {
Ok(Value::None)
} else {
Err(Error::Interp(format!("unlab-gpu version {} isn't matched to version requirement {}", version, version_req)))
}
},
_ => Err(Error::Interp(String::from("unsupported type for function reqver"))),
}
},
Some(_) => Err(Error::Interp(String::from("unsupported type for function reqver"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn docpath(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let shared_env_g = rw_lock_read(env.shared_env())?;
Ok(Value::Object(Arc::new(Object::String(shared_env_g.doc_path().to_string_lossy().into_owned()))))
}
pub fn doc(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() > 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let lib_name = match arg_values.get(0) {
Some(arg_value) => {
match arg_value.to_opt_string() {
Some(tmp_lib_name) => tmp_lib_name,
None => return Err(Error::Interp(String::from("unsupported types for function doc"))),
}
},
None => String::from("std/root"),
};
let idents = match arg_values.get(1) {
Some(arg_value) => {
match arg_value.to_opt_string() {
Some(name) => {
let name_without_first_colons = if name.starts_with("::") {
&name[2..]
} else {
name.as_str()
};
let tmp_idents: Vec<String> = name_without_first_colons.split("::").map(String::from).collect();
match tmp_idents.first() {
Some(tmp_ident) if tmp_ident == &String::from("root") => Some((&tmp_idents[1..]).to_vec()),
Some(_) => Some(tmp_idents),
None => Some(Vec::new()),
}
},
None => return Err(Error::Interp(String::from("unsupported types for function doc"))),
}
},
None => None,
};
let doc_path = {
let shared_env_g = rw_lock_read(env.shared_env())?;
OsString::from(shared_env_g.doc_path())
};
let mut res: Result<Value> = Ok(Value::None);
for dir in std::env::split_paths(doc_path.as_os_str()) {
let mut path = dir.clone();
path.push(lib_name.replace('/', path::MAIN_SEPARATOR_STR));
match &idents {
Some(idents) => {
path.push("root");
for ident in idents {
path.push(ident);
}
path.set_extension("html");
},
None => path.push("index.html"),
}
match fs::metadata(path.as_path()) {
Ok(_) => {
let canon_path = match path.canonicalize() {
Ok(tmp_canon_path) => tmp_canon_path,
Err(err) => return Err(Error::Io(err)),
};
match open_browser(canon_path) {
Ok(()) => return Ok(Value::None),
Err(err) => return Err(Error::Opener(Box::new(err))),
}
},
Err(err) if err.kind() == ErrorKind::NotFound => res = Err(Error::Io(err)),
Err(err) => return Err(Error::Io(err)),
}
}
res
}
fn assert_op<F>(arg_values: &[Value], default_msg: Option<&str>, pair: Option<(Value, Value)>, f: F) -> Result<Value>
where F: FnOnce() -> Result<bool>
{
if !f()? {
let msg = if !arg_values.is_empty() {
let mut s = String::new();
for arg_value in arg_values {
s.push_str(format!("{}", arg_value).as_str());
}
Some(s)
} else {
match default_msg {
Some(s) => Some(String::from(s)),
None => None,
}
};
return Err(Error::Assert(msg, pair));
}
Ok(Value::None)
}
pub fn assert(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 1 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match arg_values.get(0) {
Some(Value::Bool(b)) => assert_op(&arg_values[1..], None, None, || Ok(*b)),
Some(_) => Err(Error::Interp(String::from("unsupported type for fuction assert"))),
None => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn asserteq(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value), Some(value2)) => assert_op(&arg_values[2..], Some("left isn't equal to right"), Some((value.clone(), value2.clone())), || value.eq_without_types(&value2)),
_ => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn assertne(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 2 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1)) {
(Some(value), Some(value2)) => assert_op(&arg_values[2..], Some("left is equal to right"), Some((value.clone(), value2.clone())), || Ok(!value.eq_without_types(&value2)?)),
_ => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn assertnearlyeq(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(value), Some(value2), Some(eps_value @ (Value::Int(_) | Value::Float(_)))) => {
let eps = eps_value.to_f32();
assert_op(&arg_values[3..], Some("left isn't nearly equal to right"), Some((value.clone(), value2.clone())), || value.nearly_eq_without_types(&value2, eps))
},
(Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for fuction assertnearlyeq"))),
_ => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn assertnearlyne(_interp: &mut Interp, _env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() < 3 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
match (arg_values.get(0), arg_values.get(1), arg_values.get(2)) {
(Some(value), Some(value2), Some(eps_value @ (Value::Int(_) | Value::Float(_)))) => {
let eps = eps_value.to_f32();
assert_op(&arg_values[3..], Some("left is nearly equal to right"), Some((value.clone(), value2.clone())), || Ok(!value.nearly_eq_without_types(&value2, eps)?))
},
(Some(_), Some(_), Some(_)) => Err(Error::Interp(String::from("unsupported types for fuction assertnearlyne"))),
_ => Err(Error::Interp(String::from("no argument"))),
}
}
pub fn tests(_interp: &mut Interp, env: &mut Env, arg_values: &[Value]) -> Result<Value>
{
if arg_values.len() != 0 {
return Err(Error::Interp(String::from("invalid number of arguments")));
}
let mut shared_env_g = rw_lock_write(env.shared_env())?;
shared_env_g.add_test_suite(env.mod_idents().to_vec());
Ok(Value::None)
}
pub fn add_builtin_fun(root_mod: &mut ModNode<Value, ()>, ident: String, f: fn(&mut Interp, &mut Env, &[Value]) -> Result<Value>)
{ root_mod.add_var(ident.clone(), Value::Object(Arc::new(Object::BuiltinFun(ident, f)))) }
pub fn add_alias(root_mod: &mut ModNode<Value, ()>, new_ident: String, old_ident: &String)
{
match root_mod.var(old_ident) {
Some(value) => root_mod.add_var(new_ident, value.clone()),
None => (),
}
}
pub fn add_std_builtin_funs(root_mod: &mut ModNode<Value, ()>)
{
root_mod.add_var(String::from("pi"), Value::Float(f32::consts::PI));
root_mod.add_var(String::from("e"), Value::Float(f32::consts::E));
root_mod.add_var(String::from("eps"), Value::Float(f32::EPSILON));
root_mod.add_var(String::from("pathsep"), Value::Object(Arc::new(Object::String(format!("{}", path::MAIN_SEPARATOR)))));
add_builtin_fun(root_mod, String::from("type"), typ);
add_builtin_fun(root_mod, String::from("clone"), clone);
add_builtin_fun(root_mod, String::from("bool"), boolean);
add_builtin_fun(root_mod, String::from("int"), int);
add_builtin_fun(root_mod, String::from("float"), float);
add_builtin_fun(root_mod, String::from("string"), string);
add_builtin_fun(root_mod, String::from("zeros"), zeros);
add_builtin_fun(root_mod, String::from("ones"), ones);
add_builtin_fun(root_mod, String::from("eye"), eye);
add_builtin_fun(root_mod, String::from("init"), init);
add_builtin_fun(root_mod, String::from("initdiag"), initdiag);
add_builtin_fun(root_mod, String::from("matrix"), matrix);
add_builtin_fun(root_mod, String::from("rowvector"), rowvector);
add_builtin_fun(root_mod, String::from("colvector"), colvector);
add_builtin_fun(root_mod, String::from("matrixarray"), matrixarray);
add_builtin_fun(root_mod, String::from("error"), error);
add_builtin_fun(root_mod, String::from("array"), array);
add_builtin_fun(root_mod, String::from("strong"), strong);
add_builtin_fun(root_mod, String::from("weak"), weak);
add_builtin_fun(root_mod, String::from("isempty"), isempty);
add_builtin_fun(root_mod, String::from("length"), length);
add_builtin_fun(root_mod, String::from("rows"), rows);
add_builtin_fun(root_mod, String::from("columns"), columns);
add_builtin_fun(root_mod, String::from("get"), get);
add_builtin_fun(root_mod, String::from("getdiag"), getdiag);
add_builtin_fun(root_mod, String::from("split"), split);
add_builtin_fun(root_mod, String::from("trim"), trim);
add_builtin_fun(root_mod, String::from("contains"), contains);
add_builtin_fun(root_mod, String::from("startswith"), startswith);
add_builtin_fun(root_mod, String::from("endswith"), endswith);
add_builtin_fun(root_mod, String::from("replace"), replace);
add_builtin_fun(root_mod, String::from("upper"), upper);
add_builtin_fun(root_mod, String::from("lower"), lower);
add_builtin_fun(root_mod, String::from("sort"), sort);
add_builtin_fun(root_mod, String::from("reverse"), reverse);
add_builtin_fun(root_mod, String::from("any"), any);
add_builtin_fun(root_mod, String::from("all"), all);
add_builtin_fun(root_mod, String::from("find"), find);
add_builtin_fun(root_mod, String::from("filter"), filter);
add_builtin_fun(root_mod, String::from("max"), max);
add_builtin_fun(root_mod, String::from("min"), min);
add_builtin_fun(root_mod, String::from("imax"), imax);
add_builtin_fun(root_mod, String::from("imin"), imin);
add_builtin_fun(root_mod, String::from("push"), push);
add_builtin_fun(root_mod, String::from("pop"), pop);
add_builtin_fun(root_mod, String::from("append"), append);
add_builtin_fun(root_mod, String::from("insert"), insert);
add_builtin_fun(root_mod, String::from("remove"), remove);
add_builtin_fun(root_mod, String::from("errorkind"), errorkind);
add_builtin_fun(root_mod, String::from("errormsg"), errormsg);
add_builtin_fun(root_mod, String::from("isequal"), isequal);
add_builtin_fun(root_mod, String::from("isnotequal"), isnotequal);
add_builtin_fun(root_mod, String::from("isless"), isless);
add_builtin_fun(root_mod, String::from("isgreaterequal"), isgreaterequal);
add_builtin_fun(root_mod, String::from("isgreater"), isgreater);
add_builtin_fun(root_mod, String::from("islessequal"), islessequal);
add_builtin_fun(root_mod, String::from("sigmoid"), sigmoid);
add_builtin_fun(root_mod, String::from("tanh"), tanh);
add_builtin_fun(root_mod, String::from("swish"), swish);
add_builtin_fun(root_mod, String::from("softmax"), softmax);
add_builtin_fun(root_mod, String::from("sqrt"), sqrt);
add_builtin_fun(root_mod, String::from("reallytranspose"), reallytranspose);
add_alias(root_mod, String::from("rt"), &String::from("reallytranspose"));
add_builtin_fun(root_mod, String::from("repeat"), repeat);
add_builtin_fun(root_mod, String::from("mod"), modulo);
add_builtin_fun(root_mod, String::from("abs"), abs);
add_builtin_fun(root_mod, String::from("pow"), pow);
add_builtin_fun(root_mod, String::from("exp"), exp);
add_builtin_fun(root_mod, String::from("log"), log);
add_builtin_fun(root_mod, String::from("log2"), log2);
add_builtin_fun(root_mod, String::from("log10"), log10);
add_builtin_fun(root_mod, String::from("sin"), sin);
add_builtin_fun(root_mod, String::from("cos"), cos);
add_builtin_fun(root_mod, String::from("tan"), tan);
add_builtin_fun(root_mod, String::from("asin"), asin);
add_builtin_fun(root_mod, String::from("acos"), acos);
add_builtin_fun(root_mod, String::from("atan"), atan);
add_builtin_fun(root_mod, String::from("atan2"), atan2);
add_builtin_fun(root_mod, String::from("sinh"), sinh);
add_builtin_fun(root_mod, String::from("cosh"), cosh);
add_builtin_fun(root_mod, String::from("asinh"), asinh);
add_builtin_fun(root_mod, String::from("acosh"), acosh);
add_builtin_fun(root_mod, String::from("atanh"), atanh);
add_builtin_fun(root_mod, String::from("sign"), sign);
add_builtin_fun(root_mod, String::from("ceil"), ceil);
add_builtin_fun(root_mod, String::from("floor"), floor);
add_builtin_fun(root_mod, String::from("round"), round);
add_builtin_fun(root_mod, String::from("trunc"), trunc);
add_builtin_fun(root_mod, String::from("rand"), rand);
add_builtin_fun(root_mod, String::from("randi"), randi);
add_builtin_fun(root_mod, String::from("str2int"), str2int);
add_builtin_fun(root_mod, String::from("str2float"), str2float);
add_builtin_fun(root_mod, String::from("hex2dec"), hex2dec);
add_builtin_fun(root_mod, String::from("char2code"), char2code);
add_builtin_fun(root_mod, String::from("code2char"), code2char);
add_builtin_fun(root_mod, String::from("formatmillis"), formatmillis);
add_builtin_fun(root_mod, String::from("withwidth"), withwidth);
add_builtin_fun(root_mod, String::from("withzeros"), withzeros);
add_builtin_fun(root_mod, String::from("readline"), readline);
add_builtin_fun(root_mod, String::from("format"), format);
add_builtin_fun(root_mod, String::from("print"), print);
add_builtin_fun(root_mod, String::from("println"), println);
add_builtin_fun(root_mod, String::from("eprint"), eprint);
add_builtin_fun(root_mod, String::from("eprintln"), eprintln);
add_builtin_fun(root_mod, String::from("flush"), flush);
add_builtin_fun(root_mod, String::from("eflush"), eflush);
add_builtin_fun(root_mod, String::from("cd"), cd);
add_builtin_fun(root_mod, String::from("pwd"), pwd);
add_builtin_fun(root_mod, String::from("exist"), exist);
add_builtin_fun(root_mod, String::from("filetype"), filetype);
add_builtin_fun(root_mod, String::from("dir"), dir);
add_alias(root_mod, String::from("ls"), &String::from("dir"));
add_builtin_fun(root_mod, String::from("mkdir"), mkdir);
add_builtin_fun(root_mod, String::from("rmdir"), rmdir);
add_builtin_fun(root_mod, String::from("rmfile"), rmfile);
add_builtin_fun(root_mod, String::from("copy"), copy);
add_builtin_fun(root_mod, String::from("rename"), rename);
add_builtin_fun(root_mod, String::from("spawn"), spawn);
add_builtin_fun(root_mod, String::from("exit"), exit);
add_builtin_fun(root_mod, String::from("load"), load);
add_builtin_fun(root_mod, String::from("save"), save);
add_builtin_fun(root_mod, String::from("loadstr"), loadstr);
add_builtin_fun(root_mod, String::from("savestr"), savestr);
add_builtin_fun(root_mod, String::from("loadtoml"), loadtoml);
add_builtin_fun(root_mod, String::from("savetoml"), savetoml);
add_builtin_fun(root_mod, String::from("loadjson"), loadjson);
add_builtin_fun(root_mod, String::from("savejson"), savejson);
add_builtin_fun(root_mod, String::from("args"), args);
add_builtin_fun(root_mod, String::from("env"), env);
add_builtin_fun(root_mod, String::from("scriptdir"), scriptdir);
add_builtin_fun(root_mod, String::from("libpath"), libpath);
add_builtin_fun(root_mod, String::from("domain"), domain);
add_builtin_fun(root_mod, String::from("uselib"), uselib);
add_builtin_fun(root_mod, String::from("reuselib"), reuselib);
add_builtin_fun(root_mod, String::from("run"), run);
add_alias(root_mod, String::from("runwithdoc"), &String::from("run"));
add_builtin_fun(root_mod, String::from("clock"), clock);
add_builtin_fun(root_mod, String::from("usemod"), usemod);
add_builtin_fun(root_mod, String::from("usemods"), usemods);
add_builtin_fun(root_mod, String::from("usevar"), usevar);
add_builtin_fun(root_mod, String::from("usevars"), usevars);
add_builtin_fun(root_mod, String::from("removeusemod"), removeusemod);
add_builtin_fun(root_mod, String::from("removeusevar"), removeusevar);
add_builtin_fun(root_mod, String::from("removemod"), removemod);
add_builtin_fun(root_mod, String::from("removevar"), removevar);
add_builtin_fun(root_mod, String::from("removelocalvar"), removelocalvar);
add_builtin_fun(root_mod, String::from("checkintr"), checkintr);
add_builtin_fun(root_mod, String::from("backend"), backend);
add_builtin_fun(root_mod, String::from("version"), version);
add_builtin_fun(root_mod, String::from("reqver"), reqver);
add_builtin_fun(root_mod, String::from("docpath"), docpath);
add_builtin_fun(root_mod, String::from("doc"), doc);
add_alias(root_mod, String::from("help"), &String::from("doc"));
add_builtin_fun(root_mod, String::from("assert"), assert);
add_builtin_fun(root_mod, String::from("asserteq"), asserteq);
add_builtin_fun(root_mod, String::from("assertne"), assertne);
add_builtin_fun(root_mod, String::from("assertnearlyeq"), assertnearlyeq);
add_builtin_fun(root_mod, String::from("assertnearlyne"), assertnearlyne);
add_builtin_fun(root_mod, String::from("tests"), tests);
add_builtin_fun(root_mod, String::from("getopts"), getopts);
add_builtin_fun(root_mod, String::from("getoptsusage"), getoptsusage);
#[cfg(feature = "plot")]
add_builtin_fun(root_mod, String::from("plot"), plot);
#[cfg(feature = "plot")]
add_builtin_fun(root_mod, String::from("plot3"), plot3);
#[cfg(feature = "plot")]
add_builtin_fun(root_mod, String::from("histogram"), histogram);
#[cfg(feature = "plot")]
add_alias(root_mod, String::from("hist"), &String::from("histogram"));
}
#[cfg(test)]
mod tests;