use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::fmt;
use std::fmt::{Display, Debug, Formatter};
use crate::str_int::*;
use crate::compiler::{GlobalEnv, GlobalEnvRef};
use crate::nvec::{NVec};
use crate::ops::Prog;
use fnv::FnvHashMap;
#[derive(Debug, Clone, PartialEq)]
pub struct FileRef {
s: Rc<String>,
}
impl Display for FileRef {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{}", *self.s)
}
}
impl FileRef {
pub fn new(s: &str) -> Self {
FileRef { s: Rc::new(String::from(s)) }
}
pub fn s(&self) -> &str { &(*self.s) }
}
#[derive(Clone, PartialEq)]
pub struct SynPosInfo {
pub line: u32,
pub col: u32,
pub file: FileRef,
pub name: Option<String>,
}
#[derive(Clone, PartialEq)]
pub struct SynPos {
pub syn: Syntax,
pub info: Rc<SynPosInfo>,
}
impl SynPos {
pub fn empty() -> Self {
Self {
syn: Syntax::Block,
info: Rc::new(SynPosInfo {
line: 0,
col: 0,
file: FileRef::new("?"),
name: None,
}),
}
}
pub fn new(syn: Syntax, line: u32, col: u32, file: FileRef) -> Self {
Self {
syn,
info: Rc::new(SynPosInfo { line, col, file, name: None, }),
}
}
pub fn line(&self) -> u32 { self.info.line }
pub fn col(&self) -> u32 { self.info.col }
pub fn filename(&self) -> &str {
self.info.file.s()
}
pub fn syn(&self) -> Syntax { self.syn }
pub fn set_syn(&mut self, syn: Syntax) {
self.syn = syn;
}
pub fn set_name(&mut self, name: &str) {
let mut new_info = (*self.info).clone();
new_info.name = Some(name.to_string());
self.info = Rc::new(new_info);
}
pub fn s_short(&self) -> String {
format!("[{},{}({:?})]", self.info.line, self.info.col, self.syn)
}
pub fn s_only_pos(&self) -> String {
format!("[{},{}:{}]", self.info.line, self.info.col, self.info.file.s())
}
}
impl Display for SynPos {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
if self.info.line > 0 {
if self.info.name.is_some() && !self.info.name.as_ref().unwrap().is_empty() {
write!(f, "[{},{}:{}({:?})@{}]",
self.info.line, self.info.col, self.info.file.s(), self.syn,
self.info.name.as_ref().unwrap())
} else {
write!(f, "[{},{}:{}({:?})]",
self.info.line, self.info.col, self.info.file.s(), self.syn)
}
} else {
write!(f, "")
}
}
}
impl Debug for SynPos {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CompileError {
pub pos: SynPos,
pub msg: String,
}
impl Display for CompileError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"[{},{}:{}] Compilation Error: {}",
self.pos.info.line, self.pos.info.col, self.pos.info.file, self.msg)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(dead_code)]
pub enum Syntax {
Var,
Key,
SetKey,
GetKey,
GetKey2,
GetKey3,
GetSym,
GetSym2,
GetSym3,
GetIdx,
GetIdx2,
GetIdx3,
BinOpAdd,
BinOpSub,
BinOpMul,
BinOpDiv,
BinOpMod,
BinOpLe,
BinOpLt,
BinOpGe,
BinOpGt,
BinOpEq,
OpNewPair,
OpCallLwR,
OpCallRwL,
OpCallApplyLwR,
OpCallApplyRwL,
OpColAddL,
OpColAddR,
Str,
Lst,
IVec,
FVec,
Opt,
Iter,
Map,
Expr,
Func,
Block,
Err,
Call,
Apply,
And,
Or,
Assign,
Def,
Ref,
HRef,
WRef,
Deref,
CaptureRef,
AssignRef,
DefGlobRef,
DefConst,
SelfObj,
SelfData,
Import,
Export,
DumpStack,
DumpVM,
DebugPrint,
MapSplice,
VecSplice,
Accum,
GlobVar,
Selector,
Pattern,
StructPattern,
Formatter,
}
#[derive(Clone)]
pub struct Stdio {
pub write: Rc<RefCell<dyn std::io::Write>>,
pub read: Rc<RefCell<dyn std::io::BufRead>>,
}
impl Stdio {
pub fn new_rust_std() -> Self {
Self {
write: Rc::new(RefCell::new(std::io::stdout())),
read: Rc::new(RefCell::new(std::io::BufReader::new(std::io::stdin()))),
}
}
pub fn new_from_mem(input: Rc<RefCell<std::io::Cursor<Vec<u8>>>>,
output: Rc<RefCell<Vec<u8>>>)
-> Self
{
Self {
write: output,
read: input,
}
}
}
impl std::fmt::Debug for Stdio {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "wlambda::vval::Stdio")
}
}
const START_STACK_SIZE : usize = 512;
#[derive(Default, Debug, Clone, Copy)]
pub struct LoopInfo {
pub pc: usize,
pub uw_depth: usize,
pub sp: usize,
pub break_pc: usize,
}
impl LoopInfo {
#[inline]
pub fn new() -> Self {
Self { pc: 0, uw_depth: 0, sp: 0, break_pc: 0 }
}
}
#[derive(Debug, Clone)]
pub enum UnwindAction {
Null,
RestoreAccum(VVal, VVal),
RestoreSP(usize),
ClearLocals(usize, usize),
RestoreSelf(VVal),
RestoreLoopInfo(LoopInfo),
RestoreIter(Option<Rc<RefCell<VValIter>>>),
FunctionCall(usize, usize, usize),
}
#[derive(Debug)]
pub struct Env {
pub args: std::vec::Vec<VVal>,
pub call_stack: std::vec::Vec<Rc<VValFun>>,
pub unwind_stack: std::vec::Vec<UnwindAction>,
pub current_self: VVal,
pub bp: usize,
pub sp: usize,
pub argc: usize,
pub user: Rc<RefCell<dyn std::any::Any>>,
pub exports: FnvHashMap<Symbol, VVal>,
pub stdio: Stdio,
pub accum_val: VVal,
pub accum_fun: VVal,
pub global: GlobalEnvRef,
pub vm_nest: usize,
pub loop_info: LoopInfo,
pub iter: Option<Rc<RefCell<VValIter>>>,
}
impl Env {
pub fn new(global: GlobalEnvRef) -> Env {
let mut e = Env {
args: Vec::with_capacity(START_STACK_SIZE),
current_self: VVal::None,
bp: 0,
sp: 0,
argc: 0,
user: Rc::new(RefCell::new(VVal::vec())),
exports: FnvHashMap::with_capacity_and_hasher(5, Default::default()),
stdio: Stdio::new_rust_std(),
accum_fun: VVal::None,
accum_val: VVal::None,
call_stack: vec![],
unwind_stack: vec![],
loop_info: LoopInfo::new(),
iter: None,
vm_nest: 0,
global
};
e.args.resize(START_STACK_SIZE, VVal::None);
e
}
pub fn new_with_user(global: GlobalEnvRef, user: Rc<RefCell<dyn std::any::Any>>) -> Env {
let mut e = Env {
args: Vec::with_capacity(START_STACK_SIZE),
current_self: VVal::None,
bp: 0,
sp: 0,
argc: 0,
exports: FnvHashMap::with_capacity_and_hasher(2, Default::default()),
stdio: Stdio::new_rust_std(),
accum_fun: VVal::None,
accum_val: VVal::None,
call_stack: vec![],
unwind_stack: std::vec::Vec::with_capacity(1000),
loop_info: LoopInfo::new(),
iter: None,
vm_nest: 0,
user,
global,
};
e.args.resize(START_STACK_SIZE, VVal::None);
e
}
pub fn set_stdio(&mut self, stdio: Stdio) {
self.stdio = stdio;
}
pub fn get_user(&self) -> Rc<RefCell<dyn std::any::Any>> {
self.user.clone()
}
#[allow(dead_code)]
pub fn with_user_do<T: 'static, F, X>(&mut self, f: F) -> X
where F: Fn(&mut T) -> X {
let mut any = self.user.borrow_mut();
let ref_reg = any.downcast_mut::<T>().unwrap();
f(ref_reg)
}
pub fn export_name(&mut self, name: &str, value: &VVal) {
self.exports.insert(s2sym(name), value.clone());
}
#[inline]
pub fn set_bp(&mut self, env_size: usize) -> usize {
let new_bp = self.sp;
self.sp += env_size;
if self.sp >= self.args.len() {
self.args.resize(self.sp * 2, VVal::None);
}
std::mem::replace(&mut self.bp, new_bp)
}
#[inline]
pub fn reset_bp(&mut self, env_size: usize, oldbp: usize) {
for i in self.bp..self.sp {
self.args[i] = VVal::None;
}
self.popn(env_size);
self.bp = oldbp;
}
pub fn self_object(&self) -> VVal {
self.current_self.clone()
}
#[inline]
pub fn with_object<T>(&mut self, object: VVal, f: T) -> Result<VVal, StackAction>
where T: Fn(&mut Env) -> Result<VVal, StackAction> {
let old_self = std::mem::replace(&mut self.current_self, object);
let ret = f(self);
self.current_self = old_self;
ret
}
#[inline]
pub fn with_local_call_info<T>(&mut self, argc: usize, f: T) -> Result<VVal, StackAction>
where T: Fn(&mut Env) -> Result<VVal, StackAction> {
let local_size = 0;
let old_argc = std::mem::replace(&mut self.argc, argc);
let old_bp = self.set_bp(local_size);
let ret = f(self);
self.reset_bp(local_size, old_bp);
self.argc = old_argc;
ret
}
#[inline]
pub fn with_restore_sp<T>(&mut self, f: T) -> Result<VVal, StackAction>
where T: Fn(&mut Env) -> Result<VVal, StackAction> {
let old_sp = self.sp;
let ret = f(self);
self.popn(self.sp - old_sp);
ret
}
#[inline]
pub fn push_sp(&mut self, n: usize) {
self.sp += n;
if self.sp >= self.args.len() {
self.args.resize(self.sp * 2, VVal::None);
}
}
#[inline]
pub fn push(&mut self, v: VVal) -> usize {
if self.sp >= self.args.len() {
self.args.resize(self.sp * 2, VVal::None);
}
self.args[self.sp] = v;
self.sp += 1;
self.sp - 1
}
#[inline]
pub fn stk(&self, offs: usize) -> &VVal {
&self.args[self.sp - offs] }
#[inline]
pub fn stk_i(&self, offs: usize) -> i64 {
if let VVal::Int(i) = &self.args[(self.sp - 1) + offs] {
*i
} else {
0
}
}
#[inline]
pub fn inc_local(&mut self, idx: usize, inc: i16) -> i64 {
if let VVal::Int(i) = &mut self.args[self.bp + idx] {
if inc > 0 { *i += 1; }
else { *i -= 1; }
*i
} else {
0
}
}
#[inline]
pub fn pop(&mut self) -> VVal {
if self.sp < 1 {
panic!("Stack pointer underflow {} {}", self.sp, 1);
}
self.sp -= 1;
std::mem::replace(&mut self.args[self.sp], VVal::None)
}
#[inline]
pub fn null_locals(&mut self, from: usize, to: usize) {
for i in from..to {
self.args[self.bp + i] = VVal::None;
}
}
#[inline]
pub fn popn(&mut self, n: usize) {
if self.sp < n {
panic!("Stack pointer underflow {} {}", self.sp, n);
}
if n > 0 {
for i in (self.sp - n)..self.sp {
self.args[i] = VVal::None;
}
}
self.sp -= n;
}
pub fn dump_stack(&self) {
for (i, v) in self.args.iter().enumerate() {
let mut mark = String::from("");
if i == self.bp { mark = format!("{} BP", mark); }
if i == self.sp { mark = format!("{} SP", mark); }
if !mark.is_empty() { mark = format!("{} ->", mark); }
println!(" {:9} [{:3}] = {}", mark, i, v.s());
if i >= (1 + self.sp) { break; }
}
if !self.call_stack.is_empty() {
for (i, u) in self.call_stack.last().unwrap().upvalues.iter().enumerate() {
println!(" UP[{:3}] = {}", i, u.s());
}
}
}
#[inline]
pub fn argv(&self) -> VVal {
VVal::vec_from(&self.args[(self.bp - self.argc)..self.bp])
}
#[inline]
pub fn argv_ref(&self) -> &[VVal] {
&self.args[(self.bp - self.argc)..self.bp]
}
#[inline]
pub fn get_up_raw(&mut self, i: usize) -> VVal {
self.call_stack.last().unwrap().upvalues[i].clone()
}
#[inline]
pub fn get_up_captured_ref(&self, i: usize) -> VVal {
self.call_stack.last().unwrap().upvalues[i].to_ref()
}
#[inline]
pub fn get_up(&self, i: usize) -> VVal {
match &self.call_stack.last().unwrap().upvalues[i] {
VVal::HRef(hr) => hr.borrow().clone(),
VVal::WWRef(r) => {
match r.upgrade() {
Some(v) => v.borrow().clone(),
None => VVal::None,
}
},
v => v.clone(),
}
}
#[inline]
pub fn arg_ref(&self, i: usize) -> Option<&VVal> {
if i >= self.argc { return None; }
Some(&self.args[(self.bp - self.argc) + i])
}
#[inline]
pub fn arg_err_internal(&self, i: usize) -> Option<VVal> {
let v = &self.args[(self.bp - self.argc) + i];
match v {
VVal::Err(_) => Some(v.clone()),
_ => None,
}
}
#[inline]
pub fn arg(&self, i: usize) -> VVal {
if i >= self.argc { return VVal::None; }
let v = &self.args[(self.bp - self.argc) + i];
v.clone()
}
pub fn get_local_up_promotion(&mut self, i: usize) -> VVal {
let idx = self.bp + i;
match &self.args[idx] {
VVal::HRef(r) => VVal::HRef(r.clone()),
VVal::WWRef(r) => VVal::WWRef(r.clone()),
v => {
let new_v = v.to_hidden_boxed_ref();
self.args[idx] = new_v.clone();
new_v
}
}
}
pub fn get_local_captured_ref(&self, i: usize) -> VVal {
let idx = self.bp + i;
self.args[idx].to_ref()
}
#[inline]
pub fn reg(&self, i: i32) -> VVal {
if i >= 0 {
self.get_local(i as usize)
} else {
self.stk((-i) as usize).clone()
}
}
#[inline]
pub fn get_local(&self, i: usize) -> VVal {
match &self.args[self.bp + i] {
VVal::HRef(r) => r.borrow().clone(),
v => v.clone(),
}
}
pub fn assign_ref_up(&mut self, i: usize, value: VVal) {
let fun = self.call_stack.last().unwrap().clone();
let upv = &fun.upvalues[i];
match upv {
VVal::HRef(r) => { r.borrow_mut().assign_ref(value); }
VVal::WWRef(l) => {
if let Some(r) = l.upgrade() {
r.borrow_mut().assign_ref(value);
}
},
_ => (),
}
}
pub fn assign_ref_local(&mut self, i: usize, value: VVal) {
let idx = self.bp + i;
self.args[idx].assign_ref(value);
}
pub fn set_up(&mut self, index: usize, value: VVal) {
let fun = self.call_stack.last().unwrap().clone();
let upv = &fun.upvalues[index];
match upv {
VVal::HRef(r) => { r.replace(value); }
VVal::WWRef(r) => {
if let Some(r) = Weak::upgrade(r) {
r.replace(value);
}
},
_ => {}
}
}
#[inline]
pub fn set_consume(&mut self, i: usize, value: VVal) {
let idx = self.bp + i;
if idx >= self.args.len() {
self.args.resize(idx * 2, VVal::None);
}
match &mut self.args[idx] {
VVal::HRef(r) => { r.replace(value); }
v => { *v = value }
}
}
#[inline]
pub fn unwind_depth(&self) -> usize {
self.unwind_stack.len()
}
#[inline]
pub fn push_unwind(&mut self, uwa: UnwindAction) {
self.unwind_stack.push(uwa);
}
#[inline]
pub fn unwind_to_depth(&mut self, depth: usize) {
while self.unwind_stack.len() > depth {
self.unwind_one();
}
}
#[inline]
pub fn push_fun_call(&mut self, fu: Rc<VValFun>, argc: usize) {
let local_size = fu.local_size;
let old_bp = self.set_bp(local_size);
let uwa =
UnwindAction::FunctionCall(
std::mem::replace(&mut self.argc, argc),
old_bp,
local_size);
self.push_unwind(uwa);
self.call_stack.push(fu);
}
#[inline]
pub fn push_clear_locals(&mut self, from: usize, to: usize) {
self.push_unwind(UnwindAction::ClearLocals(from, to));
}
#[inline]
pub fn push_unwind_self(&mut self, new_self: VVal) {
let uwa =
UnwindAction::RestoreSelf(
std::mem::replace(&mut self.current_self, new_self));
self.push_unwind(uwa);
}
#[inline]
pub fn cleanup_loop(&mut self) {
while self.sp > self.loop_info.sp {
self.pop();
}
self.unwind_to_depth(self.loop_info.uw_depth);
}
#[inline]
pub fn push_loop_info(&mut self, current_pc: usize, break_pc: usize, uw_depth_offs: usize) {
let uw_depth = self.unwind_depth() + 1 + uw_depth_offs;
let uwa =
UnwindAction::RestoreLoopInfo(
std::mem::replace(&mut self.loop_info, LoopInfo {
pc: current_pc,
sp: self.sp,
uw_depth,
break_pc,
}));
self.push_unwind(uwa);
}
#[inline]
pub fn push_iter(&mut self, iter: Rc<RefCell<VValIter>>) {
let uwa =
UnwindAction::RestoreIter(
std::mem::replace(
&mut self.iter, Some(iter)));
self.push_unwind(uwa);
}
pub fn dump_unwind_stack(&self) -> String {
let mut s = String::new();
for i in 0..self.unwind_stack.len() {
let add =
match &self.unwind_stack[self.unwind_stack.len() - (i + 1)] {
UnwindAction::RestoreSP(sp) =>
format!("rsp({})", *sp),
UnwindAction::ClearLocals(from, to) =>
format!("cl({},{})", *from, *to),
UnwindAction::RestoreLoopInfo(li) =>
format!("loinf(uws:{},sp:{})", li.uw_depth, li.sp),
UnwindAction::RestoreAccum(_fun, _val) =>
("raccm".to_string()),
UnwindAction::RestoreSelf(_slf) =>
("rslf".to_string()),
UnwindAction::RestoreIter(_i) =>
("ritr".to_string()),
UnwindAction::FunctionCall(argc, old_bp, local_size) =>
format!("fcal({},{},{})", argc, old_bp, local_size),
UnwindAction::Null =>
("nul".to_string()),
};
if !s.is_empty() {
s += ";";
}
s += &add[..];
}
s
}
#[inline]
pub fn unwind(&mut self, ua: UnwindAction) {
match ua {
UnwindAction::RestoreSP(sp) => {
while self.sp > sp {
self.pop();
}
},
UnwindAction::ClearLocals(from, to) => {
self.null_locals(from, to);
},
UnwindAction::RestoreLoopInfo(li) => {
self.loop_info = li;
},
UnwindAction::RestoreAccum(fun, val) => {
self.accum_fun = fun;
self.accum_val = val;
},
UnwindAction::RestoreSelf(slf) => {
self.current_self = slf;
},
UnwindAction::RestoreIter(i) => {
self.iter = i;
},
UnwindAction::FunctionCall(argc, old_bp, local_size) => {
self.reset_bp(local_size, old_bp);
self.call_stack.pop();
self.argc = argc;
},
UnwindAction::Null => (),
}
}
#[inline]
pub fn unwind_one(&mut self) {
let uwa = self.unwind_stack.pop().unwrap();
self.unwind(uwa);
}
pub fn setup_accumulator(&mut self, v: VVal) {
let f =
match v {
VVal::Map(_) => {
VValFun::new_fun(
move |env: &mut Env, _argc: usize| {
let k = env.arg(0);
let v = env.arg(1);
env.accum_val.set_key(&k, v.clone())?;
Ok(v)
}, Some(2), Some(2), false)
},
_ => {
VValFun::new_fun(
move |env: &mut Env, _argc: usize| {
let v = env.arg(0);
env.accum_val.accum(&v);
Ok(v)
}, Some(1), Some(1), false)
}
};
let uwa =
UnwindAction::RestoreAccum(
std::mem::replace(&mut self.accum_fun, f),
std::mem::replace(&mut self.accum_val, v));
self.push_unwind(uwa);
}
pub fn with_accum<T>(&mut self, v: VVal, acfun: T) -> Result<VVal, StackAction>
where T: Fn(&mut Env) -> Result<VVal, StackAction>
{
self.setup_accumulator(v);
let ret = acfun(self);
let val = self.accum_val.clone();
self.unwind_one();
ret?;
Ok(val)
}
pub fn get_accum_value(&self) -> VVal {
self.accum_val.clone()
}
pub fn get_accum_function(&self) -> VVal {
self.accum_fun.clone()
}
pub fn new_err(&self, s: String) -> VVal {
for i in self.call_stack.iter().rev() {
if i.syn_pos.is_some() {
return
VVal::err(
VVal::new_str_mv(s),
i.syn_pos.clone().unwrap());
}
};
VVal::err(
VVal::new_str_mv(s),
self.call_stack.last().unwrap().syn_pos.clone().or_else(
|| Some(SynPos::empty())).unwrap())
}
}
#[derive(Clone)]
pub enum StackAction {
Panic(Box<(VVal, Vec<Option<SynPos>>)>),
Return(Box<(VVal, VVal)>),
Break(Box<VVal>),
Next,
}
impl Display for StackAction {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
StackAction::Panic(panic) => {
let stk : Vec<String> =
panic.1.iter().map(|s|
if let Some(p) = s { format!("{}", p) }
else { String::from("[?]") })
.collect();
write!(f, "{} SA::Panic({})", stk.join("=>"), panic.0.s())
},
StackAction::Return(ret) => write!(f, "SA::Return(lbl={},{})", ret.0.s(), ret.1.s()),
StackAction::Break(v) => write!(f, "SA::Break({})", v.s()),
StackAction::Next => write!(f, "SA::Next"),
}
}
}
impl Debug for StackAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self)
}
}
impl StackAction {
pub fn panic_borrow(v: &VVal) -> Self {
Self::panic_msg(format!("Can't mutate borrowed value: {}", v.s()))
}
pub fn panic_msg(err: String) -> Self {
let v = Vec::new();
StackAction::Panic(Box::new((VVal::new_str_mv(err), v)))
}
pub fn panic_str(err: String, sp: Option<SynPos>) -> Self {
let mut v = Vec::new();
v.push(sp);
StackAction::Panic(Box::new((VVal::new_str_mv(err), v)))
}
pub fn panic(err: VVal, sp: Option<SynPos>) -> Self {
let mut v = Vec::new();
v.push(sp);
StackAction::Panic(Box::new((err, v)))
}
pub fn wrap_panic(self, sp: Option<SynPos>) -> Self {
match self {
StackAction::Panic(mut panic) => {
panic.as_mut().1.push(sp);
StackAction::Panic(panic)
},
_ => self,
}
}
}
impl From<VVal> for StackAction {
fn from(v: VVal) -> StackAction {
StackAction::panic(v, None)
}
}
#[derive(Debug, Clone)]
pub enum VarPos {
NoPos,
UpValue(usize),
Local(usize),
Global(VVal),
Const(VVal),
}
pub type EvalNode = Box<dyn Fn(&mut Env) -> Result<VVal,StackAction>>;
pub type ClosNodeRef = Rc<RefCell<dyn Fn(&mut Env, usize) -> Result<VVal,StackAction>>>;
#[derive(Clone)]
pub enum FunType {
ClosureNode(ClosNodeRef),
VMProg(Rc<Prog>),
}
#[derive(Clone)]
pub struct VValFun {
pub fun: FunType,
pub upvalue_pos: Rc<std::vec::Vec<VarPos>>,
pub upvalues: std::vec::Vec<VVal>,
pub local_size: usize,
pub min_args: Option<usize>,
pub max_args: Option<usize>,
pub err_arg_ok: bool,
pub syn_pos: Option<SynPos>,
pub label: VVal,
}
impl VValFun {
pub fn new_fun<T>(fun: T, min_args: Option<usize>, max_args: Option<usize>, err_arg_ok: bool) -> VVal
where T: 'static + Fn(&mut Env, usize) -> Result<VVal, StackAction> {
VValFun::new_val(Rc::new(RefCell::new(fun)), Vec::new(), 0, min_args, max_args, err_arg_ok, None, Rc::new(vec![]))
}
pub fn new_fun_with_pos<T>(fun: T, min_args: Option<usize>, max_args: Option<usize>, err_arg_ok: bool, spos: SynPos) -> VVal
where T: 'static + Fn(&mut Env, usize) -> Result<VVal, StackAction> {
VValFun::new_val(Rc::new(RefCell::new(fun)), Vec::new(), 0, min_args, max_args, err_arg_ok, Some(spos), Rc::new(vec![]))
}
#[allow(clippy::too_many_arguments)]
pub fn new_val(fun: ClosNodeRef, upvalues: std::vec::Vec<VVal>,
env_size: usize, min_args: Option<usize>,
max_args: Option<usize>, err_arg_ok: bool, syn_pos: Option<SynPos>,
upvalue_pos: Rc<std::vec::Vec<VarPos>>) -> VVal {
VVal::Fun(Rc::new(VValFun {
upvalue_pos,
upvalues,
fun: FunType::ClosureNode(fun),
local_size: env_size,
min_args,
max_args,
err_arg_ok,
syn_pos,
label: VVal::None,
}))
}
#[allow(clippy::too_many_arguments)]
pub fn new_prog(prog: Rc<Prog>, upvalues: std::vec::Vec<VVal>,
env_size: usize, min_args: Option<usize>,
max_args: Option<usize>, err_arg_ok: bool, syn_pos: Option<SynPos>,
upvalue_pos: Rc<std::vec::Vec<VarPos>>,
label: VVal) -> VVal {
VVal::Fun(Rc::new(VValFun {
upvalue_pos,
upvalues,
fun: FunType::VMProg(prog),
local_size: env_size,
min_args,
max_args,
err_arg_ok,
syn_pos,
label
}))
}
pub fn new_dummy() -> Rc<VValFun> {
Rc::new(VValFun {
fun: FunType::ClosureNode(Rc::new(RefCell::new(|_: &mut Env, _a: usize| { Ok(VVal::None) }))),
upvalue_pos: Rc::new(vec![]),
upvalues: Vec::new(),
local_size: 0,
min_args: None,
max_args: None,
err_arg_ok: false,
syn_pos: None,
label: VVal::None,
})
}
pub fn dump_upvals(&self) -> VVal {
let v = VVal::vec();
for uv in self.upvalues.iter() {
v.push(uv.clone());
}
v
}
}
#[allow(clippy::borrowed_box)]
pub trait VValUserData {
fn s(&self) -> String { format!("$<userdata:{:p}>", self) }
fn s_raw(&self) -> String { self.s() }
fn i(&self) -> i64 { -1 }
fn byte(&self) -> u8 { self.i() as u8 }
fn c(&self) -> char { std::char::from_u32(self.i() as u32).unwrap_or('?') }
fn f(&self) -> f64 { self.i() as f64 }
fn b(&self) -> bool { true }
fn eqv(&self, _other: &Box<dyn VValUserData>) -> bool { false }
fn clone_ud(&self) -> Box<dyn VValUserData>;
fn set_key(&self, _key: &VVal, _val: VVal) -> Result<(), StackAction> { Ok(()) }
fn delete_key(&self, _key: &VVal) -> Result<VVal, StackAction> { Ok(VVal::None) }
fn get_key(&self, _key: &str) -> Option<VVal> { None }
fn call_method(&self, _key: &str, _env: &mut Env) -> Result<VVal, StackAction> { Ok(VVal::None) }
fn call(&self, _env: &mut Env) -> Result<VVal, StackAction> { Ok(VVal::None) }
fn as_any(&mut self) -> &mut dyn std::any::Any;
fn as_thread_safe_usr(&mut self) -> Option<Box<dyn crate::threads::ThreadSafeUsr>> {
None
}
}
impl std::fmt::Debug for dyn VValUserData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.s())
}
}
impl std::clone::Clone for Box<dyn VValUserData> {
fn clone(&self) -> Self {
(**self).clone_ud()
}
}
#[derive(Debug, Clone)]
pub struct DropFun {
pub fun: VVal,
}
impl Drop for DropFun {
#[allow(unused_must_use)]
fn drop(&mut self) {
let global = GlobalEnv::new_default();
let mut e = Env::new(global);
if let Err(e) = self.fun.call_internal(&mut e, 0) {
eprintln!("Error in drop function: {}", e);
}
}
}
#[derive(Debug,Clone,Copy,PartialEq)]
pub enum CollectionAdd {
Push,
Unshift,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum VValChr {
Char(char),
Byte(u8),
}
impl VValChr {
pub fn to_string(&self) -> String {
match self {
VValChr::Char(c) => format!("'{}'", format_escape_char(*c, false)),
VValChr::Byte(b) => format!("$b'{}'",
format_escape_char(
std::char::from_u32(*b as u32).unwrap_or('?'),
true)),
}
}
pub fn byte(&self) -> u8 {
match self {
VValChr::Char(c) => {
let c = *c as u32;
if c > 0xFF { b'?' } else { c as u8 }
},
VValChr::Byte(b) => *b,
}
}
pub fn c(&self) -> char {
match self {
VValChr::Char(c) => *c,
VValChr::Byte(b) =>
std::char::from_u32(*b as u32).unwrap_or('?'),
}
}
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
#[repr(u8)]
pub enum VVal {
None,
Err(Rc<RefCell<(VVal, SynPos)>>),
Bol(bool),
Sym(Symbol),
Chr(VValChr),
Str(Rc<String>),
Byt(Rc<Vec<u8>>),
Int(i64),
Flt(f64),
Syn(SynPos),
Pair(Rc<(VVal, VVal)>),
Opt(Option<Rc<VVal>>),
Iter(Rc<RefCell<VValIter>>),
Lst(Rc<RefCell<std::vec::Vec<VVal>>>),
Map(Rc<RefCell<FnvHashMap<Symbol, VVal>>>),
Fun(Rc<VValFun>),
DropFun(Rc<DropFun>),
FVec(Box<NVec<f64>>),
IVec(Box<NVec<i64>>),
Ref(Rc<RefCell<VVal>>),
HRef(Rc<RefCell<VVal>>),
WWRef(Weak<RefCell<VVal>>),
Usr(Box<dyn VValUserData>),
}
impl PartialEq for VVal {
fn eq(&self, rhs: &Self) -> bool {
self.eqv(rhs)
}
}
impl std::fmt::Debug for VValFun {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "&VValFun")
}
}
pub fn format_escape_char(c: char, narrow_ascii: bool) -> String {
match c {
'\\' => { String::from("\\\\") },
'\n' => { String::from("\\n") },
'\t' => { String::from("\\t") },
'\r' => { String::from("\\r") },
'\0' => { String::from("\\0") },
'\'' => { String::from("\\'") },
'\"' => { String::from("\\\"") },
_ if narrow_ascii
&& c.is_ascii()
&& (c.is_ascii_alphanumeric()
|| c.is_ascii_graphic()
|| c.is_ascii_punctuation()
|| c == ' ') => { format!("{}", c) },
_ if narrow_ascii => { format!("\\x{:02X}", c as u32) },
_ if !narrow_ascii && c.is_ascii_control() => { format!("\\x{:02X}", c as u32) },
_ if !narrow_ascii && c.is_control() => { c.escape_unicode().to_string() },
_ => { format!("{}", c) }
}
}
pub fn format_vval_str(s: &str, narrow_ascii: bool) -> String {
let mut v : Vec<String> =
s.chars().map(|c| { format_escape_char(c, narrow_ascii) }).collect();
v.insert(0, String::from("\""));
v.push(String::from("\""));
v.concat()
}
pub fn format_vval_byt(v: &[u8]) -> String {
let mut s = String::from("");
for b in v.iter() {
s.push(*b as char);
}
format_vval_str(&s, true)
}
struct CycleCheck {
refs: FnvHashMap<i64, i64>,
backref_counter: i64,
}
impl CycleCheck {
fn new() -> Self {
CycleCheck {
refs: FnvHashMap::with_capacity_and_hasher(2, Default::default()),
backref_counter: 1,
}
}
fn touch_walk(&mut self, v: &VVal) {
if self.touch(v).is_some() { return; }
match v {
VVal::Err(e) => self.touch_walk(&(*e).borrow().0),
VVal::Pair(b) => {
self.touch_walk(&b.0);
self.touch_walk(&b.1);
},
VVal::Opt(b) => {
if let Some(x) = b {
self.touch_walk(x);
}
},
VVal::Lst(l) => {
for v in l.borrow().iter() { self.touch_walk(v); }
},
VVal::Map(l) => {
for (_k, v) in l.borrow().iter() { self.touch_walk(&v); }
},
VVal::DropFun(f) => {
if let VVal::Fun(f) = &f.fun {
for v in f.upvalues.iter() {
self.touch_walk(v);
}
}
},
VVal::Fun(f) => {
for v in f.upvalues.iter() {
self.touch_walk(v);
}
},
VVal::Ref(l) => { self.touch_walk(&(*l).borrow()); },
VVal::HRef(l) => { self.touch_walk(&(*l).borrow()); },
VVal::WWRef(l) => {
if let Some(v) = l.upgrade() {
self.touch_walk(&(*v).borrow());
}
},
VVal::Str(_)
| VVal::Byt(_)
| VVal::None
| VVal::Bol(_)
| VVal::Sym(_)
| VVal::Syn(_)
| VVal::Iter(_)
| VVal::FVec(_)
| VVal::IVec(_)
| VVal::Int(_)
| VVal::Flt(_)
| VVal::Chr(_)
| VVal::Usr(_) => {},
}
}
fn touch(&mut self, v: &VVal) -> Option<i64> {
let id = v.ref_id()?;
if let Some(backref) = self.refs.get(&id) {
if *backref == 0 {
let bkr_count = self.backref_counter;
self.backref_counter += 1;
self.refs.insert(id, bkr_count);
Some(bkr_count)
} else {
Some(*backref)
}
} else {
self.refs.insert(id, 0);
None
}
}
fn backref(&mut self, v: &VVal) -> Option<(bool, String)> {
if let VVal::Sym(_) = v { return None; }
let id = v.ref_id()?;
if let Some(backref) = self.refs.get(&id) {
match *backref {
br if br > 0 => {
self.refs.insert(id, -br);
Some((true, format!("$<{}=>", br)))
},
br if br < 0 =>
Some((false, format!("$<{}>", -br))),
_ => None,
}
} else {
None
}
}
}
pub type VValIter =
std::iter::FromFn<Box<dyn FnMut() -> Option<(VVal, Option<VVal>)>>>;
macro_rules! swizzle_char2value {
($c: expr, $i: expr, $x: ident, $y: ident, $z: ident, $w: ident) => (
match $c.chars().nth($i).unwrap_or(' ') {
'r' => $x,
'g' => $y,
'b' => $z,
'a' => $w,
'h' => $x,
's' => $y,
'v' => $z,
'0' => $x,
'1' => $y,
'2' => $z,
'3' => $w,
'x' => $x,
'y' => $y,
'z' => $z,
'w' => $w,
_ => return VVal::None,
}
)
}
#[allow(clippy::many_single_char_names)]
fn swizzle_i(s: &str, x: i64, y: i64, z: i64, w: i64) -> VVal {
match s.len() {
2 =>
VVal::IVec(Box::new(NVec::Vec2(
swizzle_char2value!(s, 0, x, y, z, w),
swizzle_char2value!(s, 1, x, y, z, w)))),
3 =>
VVal::IVec(Box::new(NVec::Vec3(
swizzle_char2value!(s, 0, x, y, z, w),
swizzle_char2value!(s, 1, x, y, z, w),
swizzle_char2value!(s, 2, x, y, z, w)))),
4 =>
VVal::IVec(Box::new(NVec::Vec4(
swizzle_char2value!(s, 0, x, y, z, w),
swizzle_char2value!(s, 1, x, y, z, w),
swizzle_char2value!(s, 2, x, y, z, w),
swizzle_char2value!(s, 3, x, y, z, w)))),
_ => VVal::None,
}
}
#[allow(clippy::many_single_char_names)]
fn swizzle_f(s: &str, x: f64, y: f64, z: f64, w: f64) -> VVal {
match s.len() {
2 =>
VVal::FVec(Box::new(NVec::Vec2(
swizzle_char2value!(s, 0, x, y, z, w),
swizzle_char2value!(s, 1, x, y, z, w)))),
3 =>
VVal::FVec(Box::new(NVec::Vec3(
swizzle_char2value!(s, 0, x, y, z, w),
swizzle_char2value!(s, 1, x, y, z, w),
swizzle_char2value!(s, 2, x, y, z, w)))),
4 =>
VVal::FVec(Box::new(NVec::Vec4(
swizzle_char2value!(s, 0, x, y, z, w),
swizzle_char2value!(s, 1, x, y, z, w),
swizzle_char2value!(s, 2, x, y, z, w),
swizzle_char2value!(s, 3, x, y, z, w)))),
_ => VVal::None,
}
}
macro_rules! iter_next {
($i: expr) => {
if let Some((v, k)) = $i.next() {
if let Some(k) = k {
VVal::opt(VVal::pair(v, k))
} else {
VVal::opt(v)
}
} else {
VVal::opt_none()
}
}
}
macro_rules! iter_next_value {
($i: expr, $v: ident, $conv: block, $def: expr) => {
if let Some(($v, _)) = $i.next() { $conv } else { $def }
}
}
macro_rules! iter_int_a_to_b {
($a: expr, $b: expr) => {
{
let mut i = $a;
let b = $b;
std::iter::from_fn(Box::new(move || {
if i >= b { return None; }
let ret = Some((VVal::Int(i), None));
i += 1;
ret
}))
}
}
}
macro_rules! pair_key_to_iter {
($p: ident) => {
if let VVal::Iter(ai) = &$p.0 {
let ai = ai.clone();
if let VVal::Iter(bi) = &$p.1 {
let bi = bi.clone();
std::iter::from_fn(Box::new(move || {
let a = ai.borrow_mut().next();
if let Some((a, ak)) = a {
let a =
if let Some(ak) = ak {
VVal::pair(a, ak)
} else {
a
};
let b = bi.borrow_mut().next();
if let Some((b, bk)) = b {
let b =
if let Some(bk) = bk {
VVal::pair(b, bk)
} else {
b
};
Some((a, Some(b)))
} else {
None
}
} else {
None
}
}))
} else {
let mut bi = $p.1.iter();
std::iter::from_fn(Box::new(move || {
let a = ai.borrow_mut().next();
if let Some((a, ak)) = a {
let a =
if let Some(ak) = ak {
VVal::pair(a, ak)
} else {
a
};
if let Some((b, bk)) = bi.next() {
let b =
if let Some(bk) = bk {
VVal::pair(b, bk)
} else {
b
};
Some((VVal::pair(a, b), None))
} else {
None
}
} else {
None
}
}))
}
} else if $p.0.is_int() {
iter_int_a_to_b!($p.0.i(), $p.1.i())
} else {
$p.0.with_s_ref(|key: &str| -> VValIter {
let l =
match &key[..] {
"keys" => $p.1.keys(),
"values" => $p.1.values(),
"enumerate" => $p.1.enumerate(),
_ => {
return std::iter::from_fn(
Box::new(move || { None }))
}
};
if let VVal::Lst(l) = l {
let l = l.clone();
let mut idx = 0;
std::iter::from_fn(Box::new(move || {
if idx >= l.borrow().len() {
return None;
}
let r = Some((l.borrow()[idx].clone(), None));
idx += 1;
r
}))
} else {
std::iter::from_fn(Box::new(move || { None }))
}
})
}
}
}
#[allow(clippy::cognitive_complexity)]
#[allow(clippy::comparison_chain)]
#[allow(clippy::while_let_on_iterator)]
fn range_extract(from: i64, cnt: i64, val: &VVal) -> VVal {
match val {
VVal::Chr(VValChr::Char(c)) => {
let c = *c as i64;
VVal::Bol(from <= c && cnt >= c)
},
VVal::Chr(VValChr::Byte(c)) => {
let c = *c as i64;
VVal::Bol(from <= c && cnt >= c)
},
VVal::Byt(s) => {
VVal::new_byt(
s.iter()
.skip(from as usize)
.take(cnt as usize).copied().collect())
},
VVal::Str(s) => {
VVal::new_str_mv(
s.chars()
.skip(from as usize)
.take(cnt as usize).collect())
},
VVal::IVec(b) => {
let mut out = vec![];
match b.as_ref() {
NVec::Vec2(a, b) => {
if cnt == 1 {
match from {
0 => out.push(VVal::Int(*a)),
1 => out.push(VVal::Int(*b)),
_ => (),
}
} else if cnt > 1 {
match from {
0 => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
},
1 => out.push(VVal::Int(*b)),
_ => (),
}
}
},
NVec::Vec3(a, b, c) => {
if cnt == 1 {
match from {
0 => out.push(VVal::Int(*a)),
1 => out.push(VVal::Int(*b)),
2 => out.push(VVal::Int(*c)),
_ => (),
}
} else if cnt == 2 {
match from {
0 => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
},
1 => {
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
},
2 => {
out.push(VVal::Int(*c));
},
_ => (),
}
} else if cnt > 2 {
match from {
0 => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
},
1 => {
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
}
2 => out.push(VVal::Int(*c)),
_ => (),
}
}
},
NVec::Vec4(a, b, c, d) => {
if cnt == 1 {
match from {
0 => out.push(VVal::Int(*a)),
1 => out.push(VVal::Int(*b)),
2 => out.push(VVal::Int(*c)),
3 => out.push(VVal::Int(*d)),
_ => (),
}
} else if cnt == 2 {
match from {
0 => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
},
1 => {
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
},
2 => {
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
},
3 => {
out.push(VVal::Int(*d));
},
_ => (),
}
} else if cnt == 3 {
match from {
0 => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
},
1 => {
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
},
2 => {
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
},
3 => {
out.push(VVal::Int(*d));
},
_ => (),
}
} else if cnt > 2 {
match from {
0 => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
},
1 => {
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
},
2 => {
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
},
3 => {
out.push(VVal::Int(*d));
},
_ => (),
}
}
}
}
VVal::vec_mv(out)
},
VVal::FVec(b) => {
let mut out = vec![];
match b.as_ref() {
NVec::Vec2(a, b) => {
if cnt == 1 {
match from {
0 => out.push(VVal::Flt(*a)),
1 => out.push(VVal::Flt(*b)),
_ => (),
}
} else if cnt > 1 {
match from {
0 => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
},
1 => out.push(VVal::Flt(*b)),
_ => (),
}
}
},
NVec::Vec3(a, b, c) => {
if cnt == 1 {
match from {
0 => out.push(VVal::Flt(*a)),
1 => out.push(VVal::Flt(*b)),
2 => out.push(VVal::Flt(*c)),
_ => (),
}
} else if cnt == 2 {
match from {
0 => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
},
1 => {
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
},
2 => {
out.push(VVal::Flt(*c));
},
_ => (),
}
} else if cnt > 2 {
match from {
0 => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
},
1 => {
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
}
2 => out.push(VVal::Flt(*c)),
_ => (),
}
}
},
NVec::Vec4(a, b, c, d) => {
if cnt == 1 {
match from {
0 => out.push(VVal::Flt(*a)),
1 => out.push(VVal::Flt(*b)),
2 => out.push(VVal::Flt(*c)),
3 => out.push(VVal::Flt(*d)),
_ => (),
}
} else if cnt == 2 {
match from {
0 => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
},
1 => {
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
},
2 => {
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
},
3 => {
out.push(VVal::Flt(*d));
},
_ => (),
}
} else if cnt == 3 {
match from {
0 => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
},
1 => {
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
},
2 => {
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
},
3 => {
out.push(VVal::Flt(*d));
},
_ => (),
}
} else if cnt > 2 {
match from {
0 => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
},
1 => {
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
},
2 => {
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
},
3 => {
out.push(VVal::Flt(*d));
},
_ => (),
}
}
}
}
VVal::vec_mv(out)
},
VVal::Lst(l) => {
let v : Vec<VVal> =
l.borrow()
.iter()
.skip(from as usize)
.take(cnt as usize)
.cloned()
.collect();
VVal::vec_mv(v)
},
VVal::Iter(i) => {
let mut out = Vec::with_capacity(cnt as usize);
let mut i = i.borrow_mut();
let mut idx = 0;
while let Some((v, _)) = i.next() {
if idx >= (from as usize) && idx < ((from + cnt) as usize) {
out.push(v);
}
idx += 1;
}
VVal::vec_mv(out)
},
_ => VVal::None,
}
}
fn pair_extract(a: &VVal, b: &VVal, val: &VVal) -> VVal {
match val {
VVal::Int(i) =>
if i % 2 == 0 { a.clone() }
else { b.clone() },
VVal::Byt(_) => {
match (a, b) {
(VVal::Int(from), VVal::Int(cnt)) => {
range_extract(*from, *cnt, val)
},
(VVal::Int(start_idx), b) if b.is_sym() || b.is_str() || b.is_byte() || b.is_char() || b.is_bytes() => {
val.find(&b, *start_idx as usize, true)
},
(VVal::Chr(_splitstr), VVal::Int(max)) => {
val.split(&a, *max as usize, true)
},
(VVal::Str(_splitstr), VVal::Int(max)) => {
val.split(&a, *max as usize, true)
},
(VVal::Byt(_splitstr), VVal::Int(max)) => {
val.split(&a, *max as usize, true)
},
(VVal::Str(_needle), b) if b.is_sym() || b.is_str() || b.is_byte() || b.is_char() || b.is_bytes() => {
val.bytes_replace(&a, &b)
},
(VVal::Byt(_needle), b) if b.is_sym() || b.is_str() || b.is_byte() || b.is_char() || b.is_bytes() => {
val.bytes_replace(&a, &b)
},
(VVal::Chr(_needle), b) if b.is_sym() || b.is_str() || b.is_byte() || b.is_char() || b.is_bytes() => {
val.bytes_replace(&a, &b)
},
_ => VVal::None
}
},
VVal::Str(s) => {
match (a, b) {
(VVal::Int(from), VVal::Int(cnt)) => {
range_extract(*from, *cnt, val)
},
(VVal::Int(start_idx), b) if b.is_sym() || b.is_str() || b.is_byte() || b.is_char() || b.is_bytes() => {
val.find(&b, *start_idx as usize, false)
},
(VVal::Chr(_splitstr), VVal::Int(max)) => {
val.split(&a, *max as usize, false)
},
(VVal::Byt(_splitstr), VVal::Int(max)) => {
val.split(&a, *max as usize, false)
},
(VVal::Str(_splitstr), VVal::Int(max)) => {
val.split(&a, *max as usize, false)
},
(VVal::Chr(needle), VVal::Chr(replace)) => {
let mut buf = [0; 6];
let chrstr = replace.c().encode_utf8(&mut buf);
VVal::new_str_mv(
s.as_ref()
.replace(needle.c(), chrstr))
},
(VVal::Str(needle), VVal::Str(replace)) => {
VVal::new_str_mv(
s.as_ref()
.replace(
needle.as_ref(), replace.as_ref()))
},
_ => VVal::None
}
},
VVal::Lst(_) => {
match (a, b) {
(VVal::Int(from), VVal::Int(cnt)) => {
range_extract(*from, *cnt, val)
},
_ => VVal::None,
}
},
VVal::Iter(_) => {
match (a, b) {
(VVal::Int(from), VVal::Int(cnt)) => {
range_extract(*from, *cnt, val)
},
_ => VVal::None,
}
},
VVal::IVec(_) => {
match (a, b) {
(VVal::Int(from), VVal::Int(cnt)) => {
range_extract(*from, *cnt, val)
},
_ => VVal::None,
}
},
VVal::FVec(_) => {
match (a, b) {
(VVal::Int(from), VVal::Int(cnt)) => {
range_extract(*from, *cnt, val)
},
_ => VVal::None,
}
},
VVal::Chr(VValChr::Byte(c)) => {
match (a, b) {
(VVal::Chr(from), VVal::Chr(to)) => {
let a = from.c() as u32;
let b = to.c() as u32;
let c = *c as u32;
VVal::Bol(a <= c && b >= c)
},
(VVal::Int(a), VVal::Int(b)) => {
let c = *c as i64;
VVal::Bol(*a <= c && *b >= c)
},
_ => VVal::None,
}
},
VVal::Chr(VValChr::Char(c)) => {
match (a, b) {
(VVal::Chr(from), VVal::Chr(to)) => {
let a = from.c() as u32;
let b = to.c() as u32;
let c = *c as u32;
VVal::Bol(a <= c && b >= c)
},
(VVal::Int(a), VVal::Int(b)) => {
let c = *c as i64;
VVal::Bol(*a <= c && *b >= c)
},
_ => VVal::None,
}
},
_ => VVal::None
}
}
fn vval_rc_ptr_eq(v: &VVal, l: &Rc<RefCell<VVal>>) -> bool {
match v {
VVal::Ref(r2) => Rc::ptr_eq(l, r2),
VVal::HRef(r2) => Rc::ptr_eq(l, r2),
VVal::WWRef(r2) =>
match r2.upgrade() {
Some(v2) => Rc::ptr_eq(l, &v2),
None => false,
},
_ => false,
}
}
fn concat_operation(bytes: bool, first: &VVal, argc: usize, env: &mut Env) -> Result<VVal, StackAction> {
if bytes {
let mut buf = first.with_bv_ref(|bv| bv.to_vec());
for i in 0..argc {
env.arg_ref(i).unwrap().with_bv_ref(|bv|
buf.extend_from_slice(bv));
}
Ok(VVal::new_byt(buf))
} else {
let mut st = first.with_s_ref(|s: &str| String::from(s));
for i in 0..argc {
env.arg_ref(i).unwrap().with_s_ref(|s: &str| st += s);
}
Ok(VVal::new_str_mv(st))
}
}
#[allow(dead_code)]
impl VVal {
#[inline]
pub fn new_str(s: &str) -> VVal {
VVal::Str(Rc::new(String::from(s)))
}
#[inline]
pub fn new_str_mv(s: String) -> VVal {
VVal::Str(Rc::new(s))
}
#[inline]
pub fn new_char(c: char) -> VVal {
VVal::Chr(VValChr::Char(c))
}
#[inline]
pub fn new_byte(b: u8) -> VVal {
VVal::Chr(VValChr::Byte(b))
}
#[inline]
pub fn new_sym(s: &str) -> VVal {
VVal::Sym(s2sym(s))
}
#[inline]
pub fn new_sym_mv(s: String) -> VVal {
VVal::Sym(new_sym_mv(s))
}
#[inline]
pub fn new_byt(v: Vec<u8>) -> VVal {
VVal::Byt(Rc::new(v))
}
#[inline]
pub fn err(v: VVal, pos: SynPos) -> VVal {
VVal::Err(Rc::new(RefCell::new((v, pos))))
}
pub fn err_msg(s: &str) -> VVal {
VVal::Err(Rc::new(RefCell::new(
(VVal::new_str(s), SynPos::empty()))))
}
pub fn new_usr<T: VValUserData + 'static>(o: T) -> VVal {
VVal::Usr(Box::new(o))
}
#[inline]
pub fn ivec2(x: i64, y: i64) -> VVal {
VVal::IVec(Box::new(NVec::Vec2(x, y)))
}
#[inline]
pub fn ivec3(x: i64, y: i64, z: i64) -> VVal {
VVal::IVec(Box::new(NVec::Vec3(x, y, z)))
}
#[inline]
pub fn ivec4(x: i64, y: i64, z: i64, w: i64) -> VVal {
VVal::IVec(Box::new(NVec::Vec4(x, y, z, w)))
}
#[inline]
pub fn fvec2(x: f64, y: f64) -> VVal {
VVal::FVec(Box::new(NVec::Vec2(x, y)))
}
#[inline]
pub fn fvec3(x: f64, y: f64, z: f64) -> VVal {
VVal::FVec(Box::new(NVec::Vec3(x, y, z)))
}
#[inline]
pub fn fvec4(x: f64, y: f64, z: f64, w: f64) -> VVal {
VVal::FVec(Box::new(NVec::Vec4(x, y, z, w)))
}
pub fn ivec_from_tpl2(tpl: (i64, i64)) -> VVal {
if let Some(nv) = NVec::from_tpl((tpl.0, tpl.1, None, None)) {
VVal::IVec(Box::new(nv))
} else {
VVal::None
}
}
pub fn ivec_from_tpl3(tpl: (i64, i64, i64)) -> VVal {
if let Some(nv) = NVec::from_tpl((tpl.0, tpl.1, Some(tpl.2), None)) {
VVal::IVec(Box::new(nv))
} else {
VVal::None
}
}
pub fn ivec_from_tpl4(tpl: (i64, i64, i64, i64)) -> VVal {
if let Some(nv) = NVec::from_tpl((tpl.0, tpl.1, Some(tpl.2), Some(tpl.3))) {
VVal::IVec(Box::new(nv))
} else {
VVal::None
}
}
pub fn fvec_from_tpl2(tpl: (f64, f64)) -> VVal {
if let Some(nv) = NVec::from_tpl((tpl.0, tpl.1, None, None)) {
VVal::FVec(Box::new(nv))
} else {
VVal::None
}
}
pub fn fvec_from_tpl3(tpl: (f64, f64, f64)) -> VVal {
if let Some(nv) = NVec::from_tpl((tpl.0, tpl.1, Some(tpl.2), None)) {
VVal::FVec(Box::new(nv))
} else {
VVal::None
}
}
pub fn fvec_from_tpl4(tpl: (f64, f64, f64, f64)) -> VVal {
if let Some(nv) = NVec::from_tpl((tpl.0, tpl.1, Some(tpl.2), Some(tpl.3))) {
VVal::FVec(Box::new(nv))
} else {
VVal::None
}
}
#[inline]
pub fn vec() -> VVal {
VVal::Lst(Rc::new(RefCell::new(Vec::new())))
}
#[inline]
pub fn vec1(a: VVal) -> VVal {
let v = Self::vec();
v.push(a);
v
}
#[inline]
pub fn vec2(a: VVal, b: VVal) -> VVal {
let v = Self::vec();
v.push(a);
v.push(b);
v
}
#[inline]
pub fn vec3(a: VVal, b: VVal, c: VVal) -> VVal {
let v = Self::vec();
v.push(a);
v.push(b);
v.push(c);
v
}
#[inline]
#[allow(clippy::many_single_char_names)]
pub fn vec4(a: VVal, b: VVal, c: VVal, d: VVal) -> VVal {
let v = Self::vec();
v.push(a);
v.push(b);
v.push(c);
v.push(d);
v
}
#[inline]
pub fn opt(v: VVal) -> VVal {
VVal::Opt(Some(Rc::new(v)))
}
#[inline]
pub fn opt_none() -> VVal { VVal::Opt(None) }
pub fn unwrap_opt(&self) -> VVal {
if let VVal::Opt(Some(o)) = self {
o.as_ref().clone()
} else {
VVal::None
}
}
#[inline]
pub fn pair(a: VVal, b: VVal) -> VVal {
VVal::Pair(Rc::new((a, b)))
}
pub fn as_iter(&self) -> VVal {
VVal::Iter(Rc::new(RefCell::new(self.iter())))
}
pub fn to_vec(&self) -> Vec<VVal> {
if let VVal::Lst(l) = self {
let r : Vec<VVal> = l.borrow_mut().iter().cloned().collect();
r
} else {
vec![self.clone()]
}
}
pub fn vec_from(vl: &[VVal]) -> VVal {
let mut v = Vec::new();
v.extend_from_slice(vl);
VVal::Lst(Rc::new(RefCell::new(v)))
}
pub fn vec_mv(v: Vec<VVal>) -> VVal {
VVal::Lst(Rc::new(RefCell::new(v)))
}
pub fn new_fun<T>(fun: T, min_args: Option<usize>,
max_args: Option<usize>,
err_arg_ok: bool) -> VVal
where T: 'static + Fn(&mut Env, usize) -> Result<VVal, StackAction> {
VValFun::new_val(
Rc::new(RefCell::new(fun)),
Vec::new(),
0, min_args, max_args, err_arg_ok, None,
Rc::new(vec![]))
}
pub fn call(&self, env: &mut Env, args: &[VVal]) -> Result<VVal, StackAction> {
let argc = args.len();
for v in args.iter() {
env.push(v.clone());
}
let ret = self.call_internal(env, argc);
env.popn(argc);
ret
}
pub fn compare_str(&self, b: &VVal) -> std::cmp::Ordering {
self.with_s_ref(|a: &str| b.with_s_ref(|b: &str| a.cmp(b)))
}
pub fn shallow_clone(&self) -> VVal {
match self {
VVal::Lst(l) => {
let out = VVal::vec();
for v in l.borrow().iter() { out.push(v.clone()); }
out
},
VVal::Map(m) => {
let out = VVal::map();
for (k, v) in m.borrow_mut().iter() {
if out.set_key_sym(k.clone(), v.clone()).is_err() {
continue;
}
}
out
},
VVal::Str(s) => {
VVal::new_str_mv(s.as_ref().clone())
},
v => v.with_deref(
|v| v.shallow_clone(),
|v| if let Some(v) = v { v.clone() }
else { VVal::None }),
}
}
pub fn compare_num(&self, b: &VVal) -> std::cmp::Ordering {
if self.is_float() {
self.f().partial_cmp(&b.f())
.unwrap_or(std::cmp::Ordering::Greater)
} else {
self.i().cmp(&b.i())
}
}
pub fn sort<F>(&self, compare: F)
where F: FnMut(&VVal, &VVal) -> std::cmp::Ordering
{
if let VVal::Lst(v) = self {
v.borrow_mut().sort_by(compare);
}
}
pub fn fisher_yates_shuffle<I>(&mut self, mut rand: I)
where I: FnMut() -> i64
{
if let VVal::Lst(list) = self {
let len = list.borrow().len();
if len <= 1 { return; }
for k in 1..len {
let i = len - k;
let j = rand().abs() as usize % (i + 1);
list.borrow_mut().swap(j, i);
}
}
}
pub fn split(&self, pat: &VVal, max: usize, bytes: bool) -> VVal {
let l = VVal::vec();
if bytes {
self.with_bv_ref(|inp| {
pat.with_bv_ref(|pat| {
let len = inp.len();
let ss_len = pat.len();
if ss_len > len {
l.push(VVal::new_byt(inp[..].to_vec()));
} else {
let mut i = 0;
let mut last_split_i = 0;
while i < len {
if i + ss_len > len { break; }
if inp[i..(i + ss_len)] == *pat {
l.push(
VVal::new_byt(
inp[last_split_i..i]
.to_vec()));
i += ss_len;
last_split_i = i;
if max > 0
&& (l.len() + 1) >= max as usize
{
l.push(
VVal::new_byt(
inp[last_split_i..len]
.to_vec()));
i += inp[last_split_i..len].len();
last_split_i = i + 1; break;
}
} else {
i += 1;
}
}
match last_split_i {
ls if ls < i => {
l.push(
VVal::new_byt(
inp[last_split_i..len]
.to_vec()));
},
ls if ls == i => {
l.push(VVal::new_byt(vec![]));
},
_ => (),
}
}
})
})
} else {
self.with_s_ref(|s| {
pat.with_s_ref(|pat| {
if max > 0 {
for part in s.splitn(max as usize, pat) {
l.push(VVal::new_str(part));
}
} else {
for part in s.split(pat) {
l.push(VVal::new_str(part));
}
}
})
})
}
l
}
pub fn find(&self, pat: &VVal, start_idx: usize, bytes: bool) -> VVal {
if bytes {
self.with_s_ref(|s|
pat.with_s_ref(|pat| {
if start_idx >= s.len() {
return VVal::None;
}
match s[start_idx..].find(pat) {
Some(idx) => VVal::Int((start_idx + idx) as i64),
None => VVal::None,
}
}))
} else {
self.with_bv_ref(|data|
pat.with_bv_ref(|pat| {
if pat.len() > (data.len() + start_idx) {
return VVal::None;
}
for i in start_idx..=(data.len() - pat.len()) {
if pat[..] == data[i..(i + pat.len())] {
return VVal::Int(i as i64);
}
}
VVal::None
}))
}
}
pub fn bytes_replace(&self, pat: &VVal, repl: &VVal) -> Self {
use std::cmp::Ordering;
let mut bv = self.as_bytes();
pat.with_bv_ref(|pat|
repl.with_bv_ref(|repl| {
let mut len = bv.len();
let mut i = 0;
let plen = pat.len();
let rlen = repl.len();
while i < len {
if bv[i..].starts_with(&pat[..]) {
match plen.cmp(&rlen) {
Ordering::Less => {
let len_delta = rlen - plen;
bv.resize(len + len_delta, 0);
bv.copy_within((i + plen)..len, i + rlen);
len += len_delta;
bv[i..(rlen + i)].clone_from_slice(&repl[..rlen]);
i += rlen;
}
Ordering::Greater => {
let len_delta = plen - rlen;
bv.copy_within((i + plen)..len, i + rlen);
bv.resize(len - len_delta, 0);
len -= len_delta;
bv[i..(rlen + i)].clone_from_slice(&repl[..rlen]);
}
Ordering::Equal => {
bv[i..(plen + i)].clone_from_slice(&repl[..plen]);
if plen > 0 {
i += plen - 1;
}
}
}
}
i += 1;
}
}));
VVal::new_byt(bv)
}
#[allow(clippy::while_let_on_iterator)]
pub fn reverse(&self) -> VVal {
match self.deref() {
VVal::Str(s) => {
VVal::new_str_mv(s.chars().rev().collect::<String>())
},
VVal::Byt(b) => {
VVal::new_byt(b.iter().rev().copied().collect::<Vec<u8>>())
},
VVal::Lst(l) => {
VVal::vec_mv(l.borrow().iter().rev().cloned().collect::<Vec<VVal>>())
},
VVal::IVec(b) => {
match b.as_ref() {
NVec::Vec2(a, b) =>
VVal::IVec(Box::new(NVec::Vec2(*b, *a))),
NVec::Vec3(a, b, c) =>
VVal::IVec(Box::new(NVec::Vec3(*c, *b, *a))),
NVec::Vec4(a, b, c, d) =>
VVal::IVec(Box::new(NVec::Vec4(*d, *c, *b, *a))),
}
},
VVal::FVec(b) => {
match b.as_ref() {
NVec::Vec2(a, b) =>
VVal::FVec(Box::new(NVec::Vec2(*b, *a))),
NVec::Vec3(a, b, c) =>
VVal::FVec(Box::new(NVec::Vec3(*c, *b, *a))),
NVec::Vec4(a, b, c, d) =>
VVal::FVec(Box::new(NVec::Vec4(*d, *c, *b, *a))),
}
},
VVal::Iter(i) => {
let mut out = vec![];
let mut i = i.borrow_mut();
while let Some((v, _)) = i.next() {
out.push(v);
}
out.reverse();
VVal::vec_mv(out)
},
_ => VVal::None
}
}
#[allow(clippy::while_let_on_iterator)]
pub fn keys(&self) -> VVal {
match self {
VVal::Map(m) => {
let out = VVal::vec();
for (k, _) in m.borrow_mut().iter() {
out.push(VVal::new_str_mv(k.to_string()));
}
out
},
VVal::Iter(i) => {
let out = VVal::vec();
let mut i = i.borrow_mut();
while let Some((_, k)) = i.next() {
if let Some(k) = k {
out.push(k);
}
}
out
},
VVal::Lst(l) => {
let out = VVal::vec();
for (i, _) in l.borrow_mut().iter().enumerate() {
out.push(VVal::Int(i as i64));
}
out
},
VVal::IVec(b) => {
match b.as_ref() {
NVec::Vec2(_, _) =>
VVal::vec2(VVal::Int(0), VVal::Int(1)),
NVec::Vec3(_, _, _) =>
VVal::vec3(VVal::Int(0), VVal::Int(1), VVal::Int(2)),
NVec::Vec4(_, _, _, _) =>
VVal::vec4(VVal::Int(0), VVal::Int(1), VVal::Int(2), VVal::Int(3))
}
},
VVal::FVec(b) => {
match b.as_ref() {
NVec::Vec2(_, _) =>
VVal::vec2(VVal::Int(0), VVal::Int(1)),
NVec::Vec3(_, _, _) =>
VVal::vec3(VVal::Int(0), VVal::Int(1), VVal::Int(2)),
NVec::Vec4(_, _, _, _) =>
VVal::vec4(VVal::Int(0), VVal::Int(1), VVal::Int(2), VVal::Int(3))
}
},
v => v.with_deref(
|v| v.keys(),
|_| VVal::None),
}
}
#[allow(clippy::while_let_on_iterator)]
pub fn values(&self) -> VVal {
match self {
VVal::Map(m) => {
let out = VVal::vec();
for (_, v) in m.borrow_mut().iter() {
out.push(v.clone());
}
out
},
VVal::Lst(l) => {
let out = VVal::vec();
for v in l.borrow_mut().iter() {
out.push(v.clone());
}
out
},
VVal::Iter(i) => {
let out = VVal::vec();
let mut i = i.borrow_mut();
while let Some((v, _)) = i.next() {
out.push(v);
}
out
},
VVal::IVec(b) => {
let out = VVal::vec();
match b.as_ref() {
NVec::Vec2(a, b) => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
},
NVec::Vec3(a, b, c) => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
},
NVec::Vec4(a, b, c, d) => {
out.push(VVal::Int(*a));
out.push(VVal::Int(*b));
out.push(VVal::Int(*c));
out.push(VVal::Int(*d));
}
}
out
},
VVal::FVec(b) => {
let out = VVal::vec();
match b.as_ref() {
NVec::Vec2(a, b) => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
},
NVec::Vec3(a, b, c) => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
},
NVec::Vec4(a, b, c, d) => {
out.push(VVal::Flt(*a));
out.push(VVal::Flt(*b));
out.push(VVal::Flt(*c));
out.push(VVal::Flt(*d));
}
}
out
},
v => v.with_deref(
|v| v.values(),
|_| VVal::None),
}
}
#[allow(clippy::while_let_on_iterator)]
pub fn enumerate(&self) -> VVal {
match self {
VVal::Map(m) => {
let out = VVal::vec();
for (i, _) in m.borrow_mut().iter().enumerate() {
out.push(VVal::Int(i as i64));
}
out
},
VVal::Lst(l) => {
let out = VVal::vec();
for (i, _) in l.borrow_mut().iter().enumerate() {
out.push(VVal::Int(i as i64));
}
out
},
VVal::Iter(i) => {
let out = VVal::vec();
let mut i = i.borrow_mut();
let mut c = 0;
while let Some(_) = i.next() {
out.push(VVal::Int(c));
c += 1;
}
out
},
v => v.with_deref(
|v| v.enumerate(),
|_| VVal::None),
}
}
pub fn iter_over_vvals(&self) -> bool {
self.with_deref(
|v| {
match v {
VVal::Lst(_) => true,
VVal::Map(_) => true,
VVal::Opt(_) => true,
_ => false,
}
},
|v| {
match v {
Some(VVal::Lst(_)) => true,
Some(VVal::Map(_)) => true,
Some(VVal::Opt(_)) => true,
_ => false,
}
})
}
pub fn iter(&self) -> VValIter {
match self {
VVal::Lst(l) => {
let l = l.clone();
let mut idx = 0;
std::iter::from_fn(Box::new(move || {
if idx >= l.borrow().len() { return None; }
let r = Some((l.borrow()[idx].clone(), None));
idx += 1;
r
}))
},
VVal::Map(m) => {
let m = m.clone();
let mut idx = 0;
std::iter::from_fn(Box::new(move || {
let r = match m.borrow().iter().nth(idx) {
Some((k, v)) => {
Some((v.clone(), Some(VVal::new_str(k.as_ref()))))
},
None => None,
};
idx += 1;
r
}))
},
VVal::Byt(b) => {
let b = b.clone();
let mut idx = 0;
std::iter::from_fn(Box::new(move || {
if idx >= b.len() { return None; }
let r = Some((VVal::new_byte(b[idx]), None));
idx += 1;
r
}))
},
VVal::Sym(s) => {
let s = s.clone();
let mut idx = 0;
std::iter::from_fn(Box::new(move || {
let r = match s.chars().nth(idx) {
Some(chr) => Some((VVal::new_char(chr), None)),
None => None,
};
idx += 1;
r
}))
},
VVal::Str(s) => {
let s = s.clone();
let mut idx = 0;
std::iter::from_fn(Box::new(move || {
match s[idx..].chars().next() {
Some(chr) => {
idx += chr.len_utf8();
Some((VVal::new_char(chr), None))
},
None => None,
}
}))
},
VVal::None => {
std::iter::from_fn(Box::new(move || { None }))
},
VVal::Pair(p) => {
pair_key_to_iter!(p)
},
VVal::IVec(b) => {
match b.as_ref() {
NVec::Vec2(a, b) => {
iter_int_a_to_b!(*a, *b)
},
NVec::Vec3(a, b, skip) => {
let mut i = *a;
let b = *b;
let skip = *skip;
std::iter::from_fn(Box::new(move || {
if i >= b { return None; }
let ret = Some((VVal::Int(i), None));
i += skip;
ret
}))
},
_ => { std::iter::from_fn(Box::new(move || { None })) },
}
},
VVal::FVec(b) => {
match b.as_ref() {
NVec::Vec2(a, b) => {
let mut i = *a;
let b = *b;
std::iter::from_fn(Box::new(move || {
if i >= b { return None; }
let r = Some((VVal::Flt(i), None));
i += 1.0;
r
}))
},
NVec::Vec3(a, b, s) => {
let mut i = *a;
let b = *b;
let s = *s;
std::iter::from_fn(Box::new(move || {
if i >= b { return None; }
let ret = Some((VVal::Flt(i), None));
i += s;
ret
}))
},
_ => { std::iter::from_fn(Box::new(move || { None })) },
}
},
VVal::Opt(Some(v)) => {
let x = v.as_ref().clone();
let mut used = false;
std::iter::from_fn(Box::new(move || {
if used { return None; }
used = true;
Some((x.clone(), None))
}))
},
VVal::Opt(None) => {
std::iter::from_fn(Box::new(move || { None }))
},
_ => self.with_deref(
|v| { v.iter() },
|v| if let Some(v) = v {
let x = v.clone();
let mut used = false;
std::iter::from_fn(Box::new(move || {
if used { return None; }
used = true;
Some((x.clone(), None))
}))
} else {
std::iter::from_fn(Box::new(move || { None }))
})
}
}
pub fn with_iter<F,R>(&self, mut f: F) -> R
where F: FnMut(&mut VValIter) -> R
{
if let VVal::Iter(i) = self {
f(&mut *i.borrow_mut())
} else {
let mut iter = self.iter();
f(&mut iter)
}
}
pub fn with_value_or_iter_values<T>(self, mut f: T)
where T: FnMut(VVal, Option<VVal>) -> bool
{
if let VVal::Iter(i) = self {
while let Some((v, k)) = i.borrow_mut().next() {
if !f(v, k) {
break;
}
}
} else {
f(self, None);
}
}
pub fn disable_function_arity(&self) -> VVal {
if let VVal::Fun(fu) = self {
let mut new_fu = fu.as_ref().clone();
new_fu.min_args = None;
new_fu.max_args = None;
VVal::Fun(Rc::new(new_fu))
} else {
self.clone()
}
}
pub fn clone_and_rebind_upvalues<T>(&self, f: T) -> VVal
where T: FnOnce(&std::vec::Vec<VarPos>, &mut std::vec::Vec<VVal>) -> ()
{
if let VVal::Fun(fu) = self {
let mut new_fu = fu.as_ref().clone();
f(&new_fu.upvalue_pos, &mut new_fu.upvalues);
VVal::Fun(Rc::new(new_fu))
} else {
panic!("clone_and_rebind_upvalues does not work on non functions!");
}
}
pub fn call_no_args(&self, env: &mut Env) -> Result<VVal, StackAction> {
self.call_internal(env, 0)
}
pub(crate) fn call_internal(&self, env: &mut Env, argc: usize) -> Result<VVal, StackAction> {
match self {
VVal::None => {
Err(StackAction::panic_msg("Calling $none is invalid".to_string()))
},
VVal::Fun(fu) => {
if let Some(i) = fu.min_args {
if argc < i {
return Err(StackAction::panic_str(
format!(
"function expects at least {} arguments, got {}",
i, argc),
fu.syn_pos.clone()));
}
}
if let Some(i) = fu.max_args {
if argc > i {
return Err(StackAction::panic_str(
format!(
"function expects at most {} arguments, got {}",
i, argc),
fu.syn_pos.clone()));
}
}
env.push_fun_call(fu.clone(), argc);
if !(*fu).err_arg_ok {
for i in 0..argc {
if let Some(VVal::Err(ev)) = env.arg_err_internal(i) {
return
Err(StackAction::panic_str(
format!("Error value in parameter list: {}",
ev.borrow().0.s()),
Some(ev.borrow().1.clone())));
}
}
}
let ret =
match &(*fu).fun {
FunType::ClosureNode(cn) => (cn.borrow())(env, argc),
FunType::VMProg(prog) => {
match crate::vm::vm(&*prog, env) {
Ok(v) => Ok(v),
Err(StackAction::Return(ret)) => {
if ret.0.eqv(&fu.label) {
Ok(ret.1)
} else {
Err(StackAction::Return(ret))
}
},
Err(e) => {
Err(e.wrap_panic(fu.syn_pos.clone()))
},
}
},
};
env.unwind_one();
ret
},
VVal::Bol(b) => {
env.with_local_call_info(argc, |e: &mut Env| {
let first = e.arg(0);
match first {
VVal::Lst(_) => Ok(first.at(*b as usize).unwrap_or(VVal::None)),
VVal::Pair(_) => Ok(first.at(*b as usize).unwrap_or(VVal::None)),
_ => {
let idx = if *b { 0 } else { 1 };
if argc > 0 {
let v = e.arg(idx);
if !v.is_none() {
v.call_internal(e, 0)
} else {
Ok(VVal::None)
}
} else { Ok(self.clone()) }
}
}
})
},
VVal::Err(e) => {
Err(StackAction::panic_msg(
format!("Called an error value: {}", e.borrow().0.s())))
},
VVal::Sym(sym) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc > 0 {
let v = e.arg(0);
Ok(v.get_key(&*sym).unwrap_or(VVal::None))
} else { Ok(self.clone()) }
})
},
VVal::Map(m) => {
env.with_local_call_info(argc, |e: &mut Env| {
let f = e.arg(0);
let mut ret = VVal::None;
for (k, v) in m.borrow().iter() {
e.push(v.clone());
e.push(VVal::new_str(k));
let el = f.call_internal(e, 2);
e.popn(2);
match el {
Ok(v) => { ret = v; },
Err(StackAction::Break(v)) => { ret = *v; break; },
Err(StackAction::Next) => { },
Err(e) => { return Err(e); },
}
}
Ok(ret)
})
},
VVal::Lst(l) => {
env.with_local_call_info(argc, |e: &mut Env| {
let f = e.arg(0);
let mut ret = VVal::None;
for i in l.borrow().iter() {
e.push(i.clone());
let el = f.call_internal(e, 1);
e.popn(1);
match el {
Ok(v) => { ret = v; },
Err(StackAction::Break(v)) => { ret = *v; break; },
Err(StackAction::Next) => { },
Err(e) => { return Err(e); },
}
}
Ok(ret)
})
},
VVal::Chr(VValChr::Char(_)) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc > 0 {
let first_arg = e.arg(0);
match first_arg {
VVal::Pair(p) => {
Ok(pair_extract(&p.0, &p.1, self))
},
_ => {
concat_operation(false, self, argc, e)
},
}
} else { Ok(self.clone()) }
})
},
VVal::Chr(VValChr::Byte(_)) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc > 0 {
let first_arg = e.arg(0);
match first_arg {
VVal::Pair(p) => {
Ok(pair_extract(&p.0, &p.1, self))
},
_ => {
concat_operation(true, self, argc, e)
},
}
} else { Ok(self.clone()) }
})
},
VVal::Byt(vval_bytes) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc > 0 {
let first_arg = e.arg(0);
match first_arg {
VVal::Chr(_) | VVal::Byt(_) | VVal::Str(_) => {
concat_operation(true, self, argc, e)
},
VVal::Int(arg_int) => {
if argc > 1 {
let from = arg_int as usize;
let cnt = e.arg(1).i() as usize;
let r : Vec<u8> =
vval_bytes.iter()
.skip(from).take(cnt).copied()
.collect();
Ok(VVal::new_byt(r))
} else if arg_int as usize >= vval_bytes.len() {
Ok(VVal::None)
} else {
Ok(VVal::new_byte(vval_bytes[arg_int as usize]))
}
},
VVal::Fun(_) => {
let mut ret = VVal::None;
for c in vval_bytes.iter() {
e.push(VVal::new_byt(vec![*c]));
let el = first_arg.call_internal(e, 1);
e.popn(1);
match el {
Ok(v) => { ret = v; },
Err(StackAction::Break(v)) => { ret = *v; break; },
Err(StackAction::Next) => { },
Err(e) => { return Err(e); },
}
}
Ok(ret)
},
VVal::Lst(_) => {
let from =
first_arg.at(0).unwrap_or(VVal::Int(0))
.i() as usize;
let cnt =
first_arg.at(1).unwrap_or_else(
|| VVal::Int((vval_bytes.len() - from) as i64))
.i() as usize;
let r : Vec<u8> =
vval_bytes.iter()
.skip(from).take(cnt).copied().collect();
Ok(VVal::new_byt(r))
},
VVal::Pair(p) => Ok(pair_extract(&p.0, &p.1, self)),
VVal::IVec(iv) => Ok(range_extract(iv.x_raw(), iv.y_raw(), self)),
VVal::Map(_) => Ok(self.with_s_ref(|key: &str| first_arg.get_key(key).unwrap_or(VVal::None))),
_ => Ok(VVal::None)
}
} else { Ok(self.clone()) }
})
},
VVal::Str(vval_str) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc > 0 {
let first_arg = e.arg(0);
match first_arg {
VVal::Int(arg_int) => {
if argc > 1 {
let from = arg_int as usize;
let cnt = e.arg(1).i() as usize;
Ok(VVal::new_str_mv(
vval_str
.chars().skip(from).take(cnt)
.collect()))
} else {
let r = vval_str.chars().nth(arg_int as usize);
match r {
None => Ok(VVal::None),
Some(c) => Ok(VVal::new_char(c)),
}
}
},
VVal::Fun(_) => {
let mut ret = VVal::None;
for c in vval_str.chars() {
e.push(VVal::new_str_mv(c.to_string()));
let el = first_arg.call_internal(e, 1);
e.popn(1);
match el {
Ok(v) => { ret = v; },
Err(StackAction::Break(v)) => { ret = *v; break; },
Err(StackAction::Next) => { },
Err(e) => { return Err(e); },
}
}
Ok(ret)
},
VVal::Lst(_) => {
let from = first_arg.at(0).unwrap_or(VVal::Int(0)).i() as usize;
let cnt = first_arg.at(1).unwrap_or_else(|| VVal::Int((vval_str.len() - from) as i64)).i() as usize;
let r : String = vval_str.chars().skip(from).take(cnt).collect();
Ok(VVal::new_str_mv(r))
},
VVal::Chr(_) | VVal::Byt(_) | VVal::Str(_) => {
concat_operation(false, self, argc, e)
},
VVal::Map(_) => Ok(
first_arg
.get_key(vval_str.as_ref())
.unwrap_or(VVal::None)),
VVal::Pair(p) => Ok(pair_extract(&p.0, &p.1, self)),
VVal::IVec(iv) => Ok(range_extract(iv.x_raw(), iv.y_raw(), self)),
_ => Ok(VVal::None)
}
} else { Ok(self.clone()) }
})
},
VVal::Int(i) => {
env.with_local_call_info(argc, |e: &mut Env| {
let v = e.arg(0);
if argc > 0 { Ok(v.at(*i as usize).unwrap_or(VVal::None)) }
else { Ok(self.clone()) }
})
},
VVal::Pair(p) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc == 0 {
match (&p.0, &p.1) {
(VVal::Chr(c), VVal::Int(cnt))
| (VVal::Int(cnt), VVal::Chr(c)) => {
let cnt = *cnt as usize;
match c {
VValChr::Char(c) => {
let mut s = String::with_capacity(cnt);
for _ in 0..cnt { s.push(*c); }
return Ok(VVal::new_str_mv(s));
},
VValChr::Byte(b) => {
let mut v = Vec::with_capacity(cnt);
v.resize(cnt, *b);
return Ok(VVal::new_byt(v));
},
}
},
_ => { return Ok(self.clone()); }
}
}
if argc != 1 { return Ok(self.clone()) }
Ok(pair_extract(&p.0, &p.1, e.arg_ref(0).unwrap()))
})
},
VVal::IVec(iv) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc != 1 { return Ok(self.clone()) }
Ok(range_extract(iv.x_raw(), iv.y_raw(), e.arg_ref(0).unwrap()))
})
},
VVal::Iter(i) => {
if argc == 1 {
env.with_local_call_info(argc, |e: &mut Env| {
let f = e.arg(0);
let mut ret = VVal::None;
#[allow(clippy::while_let_loop)]
loop {
let v =
if let Some((v, k)) = i.borrow_mut().next() {
if let Some(k) = k {
VVal::pair(v, k)
} else {
v
}
} else {
break;
};
e.push(v);
let el = f.call_internal(e, 1);
e.popn(1);
match el {
Ok(v) => { ret = v; },
Err(StackAction::Break(v)) => { ret = *v; break; },
Err(StackAction::Next) => { },
Err(e) => { return Err(e); },
}
}
Ok(ret)
})
} else {
Ok(iter_next!(i.borrow_mut()))
}
},
VVal::Opt(v) => {
if argc == 0 {
if let Some(v) = v {
Ok(v.as_ref().clone())
} else {
Ok(VVal::None)
}
} else {
let v =
if let Some(v) = v { v.as_ref().clone() }
else { VVal::None };
v.call_internal(env, argc)
}
},
VVal::Usr(ud) => {
env.with_local_call_info(argc, |e: &mut Env| ud.call(e))
},
VVal::Ref(v) => v.borrow().call_internal(env, argc),
VVal::HRef(v) => v.borrow().call_internal(env, argc),
VVal::WWRef(v) =>
if let Some(r) = v.upgrade() {
r.borrow().call_internal(env, argc)
} else { Ok(VVal::None) },
_ => { Ok(self.clone()) },
}
}
pub fn to_ref(&self) -> VVal {
match self {
VVal::HRef(r) => VVal::Ref(r.clone()),
VVal::Ref(r) => VVal::Ref(r.clone()),
VVal::WWRef(v) =>
if let Some(r) = v.upgrade() {
VVal::Ref(r)
} else {
VVal::Ref(Rc::new(RefCell::new(VVal::None)))
},
_ => VVal::Ref(Rc::new(RefCell::new(self.clone()))),
}
}
pub fn to_hidden_boxed_ref(&self) -> VVal {
VVal::HRef(Rc::new(RefCell::new(self.clone())))
}
pub fn assign_ref(&mut self, value: VVal) {
match self {
VVal::Ref(_) => { self.set_ref(value); },
VVal::HRef(_) => { self.set_ref(value); },
VVal::WWRef(_) => { self.set_ref(value); },
v => { *v = value; },
}
}
pub fn set_ref(&self, v: VVal) -> VVal {
match self {
VVal::Ref(r) => r.replace(v),
VVal::HRef(r) => r.replace(v),
VVal::WWRef(l) => {
if let Some(r) = l.upgrade() {
r.replace(v)
} else {
VVal::None
}
},
_ => VVal::None
}
}
pub fn hide_ref(self) -> VVal {
match self {
VVal::HRef(f) => VVal::HRef(f),
VVal::Ref(f) => VVal::HRef(f),
VVal::WWRef(f) => {
if let Some(r) = f.upgrade() {
VVal::HRef(r)
} else {
VVal::None.to_ref().hide_ref()
}
},
_ => self.to_ref().hide_ref(),
}
}
pub fn upgrade(self) -> VVal {
match self {
VVal::HRef(f) => VVal::Ref(f),
VVal::WWRef(f) => {
if let Some(r) = f.upgrade() {
VVal::Ref(r)
} else {
VVal::None.to_ref()
}
},
_ => self.to_ref(),
}
}
pub fn downgrade(self) -> VVal {
match self {
VVal::Ref(f) => VVal::WWRef(Rc::downgrade(&f)),
VVal::HRef(f) => VVal::WWRef(Rc::downgrade(&f)),
_ => self,
}
}
pub fn map() -> VVal {
VVal::Map(Rc::new(RefCell::new(FnvHashMap::with_capacity_and_hasher(2, Default::default()))))
}
pub fn map1(k: &str, v: VVal) -> VVal {
let m = VVal::map();
m.set_key_str(k, v).expect("single use");
m
}
pub fn map2(k: &str, v: VVal, k2: &str, v2: VVal) -> VVal {
let m = VVal::map();
m.set_key_str(k, v).expect("single use");
m.set_key_str(k2, v2).expect("single use");
m
}
pub fn map3(k: &str, v: VVal, k2: &str, v2: VVal, k3: &str, v3: VVal) -> VVal {
let m = VVal::map();
m.set_key_str(k, v).expect("single use");
m.set_key_str(k2, v2).expect("single use");
m.set_key_str(k3, v3).expect("single use");
m
}
pub fn sym(s: &str) -> VVal {
VVal::Sym(s2sym(s))
}
pub fn to_sym(&self) -> Symbol {
if let VVal::Sym(s) = self {
s.clone()
} else {
self.with_s_ref(|s: &str| s2sym(s))
}
}
#[allow(clippy::cast_ptr_alignment)]
pub fn ref_id(&self) -> Option<i64> {
Some(match self {
VVal::Err(r) => { &*r.borrow() as *const (VVal, SynPos) as i64 },
VVal::Str(s) => { &*s.as_ref() as *const String as i64 },
VVal::Byt(s) => { &*s.as_ref() as *const Vec<u8> as i64 },
VVal::Sym(s) => { s.ref_id() },
VVal::Lst(v) => { &*v.borrow() as *const Vec<VVal> as i64 },
VVal::Map(v) => { &*v.borrow() as *const FnvHashMap<Symbol, VVal> as i64 },
VVal::Iter(v) => { &*v.borrow() as *const VValIter as i64 },
VVal::Opt(p) => { if let Some(p) = p { &*p.as_ref() as *const VVal as i64 } else { 0 } },
VVal::Fun(f) => { &**f as *const VValFun as i64 },
VVal::DropFun(f) => { &**f as *const DropFun as i64 },
VVal::Pair(v) => { &**v as *const (VVal, VVal) as i64 },
VVal::Ref(v) => { &*v.borrow() as *const VVal as i64 },
VVal::HRef(v) => { &*v.borrow() as *const VVal as i64 },
VVal::Usr(b) => { &**b as *const dyn VValUserData as *const usize as i64 },
VVal::WWRef(r) => {
if let Some(l) = r.upgrade() {
&*l.borrow() as *const VVal as i64
} else {
return None;
}
},
_ => return None,
})
}
pub fn eqv(&self, v: &VVal) -> bool {
match self {
VVal::None => { if let VVal::None = v { true } else { false } },
VVal::Bol(ia) => { if let VVal::Bol(ib) = v { ia == ib } else { false } },
VVal::Int(ia) => { if let VVal::Int(ib) = v { ia == ib } else { false } },
VVal::Chr(ca) => { if let VVal::Chr(cb) = v { ca == cb } else { false } },
VVal::Flt(ia) => { if let VVal::Flt(ib) = v { (ia - ib).abs() < std::f64::EPSILON } else { false } },
VVal::Sym(s) => { if let VVal::Sym(ib) = v { s == ib } else { false } },
VVal::Syn(s) => { if let VVal::Syn(ib) = v { *s == *ib } else { false } },
VVal::Str(s) => { if let VVal::Str(ib) = v { *s == *ib } else { false } },
VVal::Byt(s) => { if let VVal::Byt(s2) = v { s[..] == s2[..] } else { false } },
VVal::Pair(b) => {
if let VVal::Pair(b2) = v { b.0.eqv(&b2.0) && b.1.eqv(&b2.1) }
else { false }
},
VVal::Opt(a) => {
if let VVal::Opt(b) = v {
if let Some(a) = a {
if let Some(b) = b {
a.eqv(b)
} else {
false
}
} else {
b.is_none()
}
} else {
false
}
},
VVal::Lst(l) => {
if let VVal::Lst(l2) = v { Rc::ptr_eq(l, l2) } else { false }
},
VVal::Map(l) => {
if let VVal::Map(l2) = v { Rc::ptr_eq(l, l2) } else { false }
},
VVal::Fun(l) => {
if let VVal::Fun(l2) = v { Rc::ptr_eq(l, l2) } else { false }
},
VVal::IVec(iv) => match v { VVal::IVec(v) => *v == *iv, _ => false },
VVal::FVec(fv) => match v { VVal::FVec(v) => *v == *fv, _ => false },
VVal::DropFun(l) => {
if let VVal::DropFun(l2) = v { Rc::ptr_eq(l, l2) } else { false }
},
VVal::Err(l) => {
if let VVal::Err(l2) = v { Rc::ptr_eq(l, l2) } else { false }
},
VVal::Iter(i) => {
if let VVal::Iter(i2) = v {
Rc::ptr_eq(i, i2)
} else {
false
}
},
VVal::Ref(l) => vval_rc_ptr_eq(v, l),
VVal::HRef(l) => vval_rc_ptr_eq(v, l),
VVal::WWRef(lw) => {
if let Some(l) = lw.upgrade() {
vval_rc_ptr_eq(v, &l)
} else {
false
}
},
VVal::Usr(u) => {
if let VVal::Usr(u2) = v {
u.eqv(&u2)
} else {
false
}
}
}
}
fn dump_vec_as_str(v: &Rc<RefCell<std::vec::Vec<VVal>>>, c: &mut CycleCheck) -> String {
let mut out : Vec<String> = Vec::new();
let mut first = true;
out.push(String::from("$["));
for s in v.borrow().iter().map(|v| v.s_cy(c)) {
if !first { out.push(String::from(",")); }
else { first = false; }
out.push(s);
}
out.push(String::from("]"));
out.concat()
}
fn dump_sym(s: &str) -> String {
if s.chars().all(|c|
c.is_alphanumeric()
|| c == '_' || c == '-' || c == '+'
|| c == '&' || c == '@')
{
format!(":{}", s)
} else {
format!(":\"{}\"", s)
}
}
fn dump_map_as_str(m: &Rc<RefCell<FnvHashMap<Symbol,VVal>>>, c: &mut CycleCheck) -> String {
let mut out : Vec<String> = Vec::new();
let mut first = true;
out.push(String::from("${"));
let hm = m.borrow();
let mut keys : Vec<&Symbol> = hm.keys().collect();
keys.sort();
for k in keys {
let v = hm.get(k).unwrap();
if !first { out.push(String::from(",")); }
else { first = false; }
if k.as_ref().chars().any(char::is_whitespace) {
out.push(format!("\"{}\"", k.as_ref()));
} else {
out.push(k.as_ref().to_string());
}
out.push(String::from("="));
out.push(v.s_cy(c));
}
out.push(String::from("}"));
out.concat()
}
pub fn map_ok_skip<T, R>(&self, mut op: T, skip: usize) -> Vec<R>
where T: FnMut(&VVal) -> R {
let mut res : Vec<R> = Vec::new();
if let VVal::Lst(b) = &self {
for i in b.borrow().iter().skip(skip) {
res.push(op(i));
}
}
res
}
pub fn map_skip<R, E, T>(&self, mut op: T, skip: usize) -> Result<Vec<R>, E>
where T: FnMut(&VVal) -> Result<R, E> {
let mut res : Vec<R> = Vec::new();
if let VVal::Lst(b) = &self {
for i in b.borrow().iter().skip(skip) {
res.push(op(i)?);
}
}
Ok(res)
}
pub fn unshift(&self, val: VVal) -> &VVal {
if let VVal::Lst(b) = &self {
b.borrow_mut().insert(0, val);
self
} else {
self.with_deref(move |v| { v.unshift(val); }, |_| ());
self
}
}
pub fn add(&self, vals: &[VVal], list_add: CollectionAdd) -> VVal {
let mut collection = if self.is_ref() { self.deref() } else { self.clone() };
match &collection {
VVal::Lst(lst) => {
for v in vals.iter() {
v.clone().with_value_or_iter_values(|v, _k| {
match list_add {
CollectionAdd::Push => {
lst.borrow_mut().push(v);
},
CollectionAdd::Unshift => {
lst.borrow_mut().insert(0, v);
},
}
true
});
}
},
VVal::Map(map) => {
for v in vals.iter() {
v.clone().with_value_or_iter_values(|v, k| {
match v {
VVal::Pair(_) => {
v.at(0).unwrap().with_s_ref(|k| {
map.borrow_mut().insert(s2sym(k), v.at(1).unwrap())
});
},
VVal::Lst(_) => {
v.v_(0).with_s_ref(|k|
map.borrow_mut().insert(s2sym(k), v.clone()));
},
VVal::Map(_) => {
for (vm, km) in v.iter() {
if let Some(k) = km {
k.with_s_ref(|ks|
map.borrow_mut().insert(s2sym(ks), vm.clone()));
}
}
},
_ => {
if let Some(k) = k {
k.with_s_ref(|kv|
map.borrow_mut().insert(s2sym(kv), v.clone()));
} else {
v.with_s_ref(|kv|
map.borrow_mut().insert(s2sym(kv), v.clone()));
}
},
}
true
})
}
},
VVal::Str(_) => {
let mut out = collection.with_s_ref(|s| s.to_string());
for v in vals.iter() {
v.clone().with_value_or_iter_values(|v, _k| {
v.with_s_ref(|s| out.push_str(s));
true
});
}
collection = VVal::new_str_mv(out);
},
VVal::Byt(_) => {
let mut out = collection.with_bv_ref(|b| b.to_vec());
for v in vals.iter() {
v.clone().with_value_or_iter_values(|v, _k| {
v.with_bv_ref(|b| out.extend_from_slice(b));
true
})
}
collection = VVal::new_byt(out);
},
v => {
return VVal::err_msg(
&format!("Can't add to non collection, got '{}' (type {})",
v.s(),
v.type_name()));
},
}
collection
}
pub fn insert_at(&self, index: usize, val: VVal) {
if let VVal::Lst(b) = &self {
b.borrow_mut().insert(index, val);
} else {
self.with_deref(|v| v.insert_at(index, val), |_| ())
}
}
pub fn set(&self, index: usize, val: VVal) {
if let VVal::Lst(b) = &self {
if index >= b.borrow().len() {
b.borrow_mut().resize(index + 1, VVal::None);
}
b.borrow_mut()[index] = val;
}
}
pub fn set_at(&self, index: usize, val: VVal) {
if let VVal::Lst(b) = &self {
b.borrow_mut()[index] = val;
}
}
pub fn at(&self, index: usize) -> Option<VVal> {
match self {
VVal::Byt(vval_bytes) => {
if index as usize >= vval_bytes.len() {
None
} else {
Some(VVal::new_byte(vval_bytes[index as usize]))
}
},
VVal::Str(vval_str) => {
let opt_char = vval_str.chars().nth(index as usize);
match opt_char {
None => None,
Some(char) => {
Some(VVal::new_char(char))
},
}
},
VVal::Pair(b) => {
Some(if index % 2 == 0 { b.0.clone() } else { b.1.clone() })
},
VVal::Iter(i) => {
let mut i = i.borrow_mut();
for _ in 0..index { i.next(); }
iter_next_value!(i, v, { Some(v) }, None)
},
VVal::Opt(ref b) => {
if let Some(b) = b {
b.as_ref().at(index)
} else {
None
}
},
VVal::IVec(b) => {
Some(match index {
0 => b.x(),
1 => b.y(),
2 => b.z().unwrap_or(VVal::None),
3 => b.w().unwrap_or(VVal::None),
_ => VVal::None
})
},
VVal::FVec(b) => {
Some(match index {
0 => b.x(),
1 => b.y(),
2 => b.z().unwrap_or(VVal::None),
3 => b.w().unwrap_or(VVal::None),
_ => VVal::None
})
},
VVal::Lst(b) => {
if b.borrow().len() > index {
Some(b.borrow()[index].clone())
} else {
None
}
},
v => v.with_deref(
|v| v.at(index),
|v| if let Some(v) = v { v.get_key(&format!("{}", index)) }
else { None }),
}
}
pub fn proto_data(&self) -> VVal {
match self {
VVal::Map(m) => m.borrow().get(&s2sym("_data")).cloned().unwrap_or(VVal::None),
VVal::Lst(l) => {
if l.borrow().len() > 1 {
l.borrow()[1].clone()
} else {
VVal::None
}
},
v => v.with_deref(
|v| v.proto_data(),
|_| VVal::None),
}
}
pub fn proto_lookup(&self, key: &str) -> Option<VVal> {
match self {
VVal::Map(m) => {
if let Some(func) = m.borrow().get(&s2sym(key)) {
Some(func.clone())
} else if let Some(proto) = m.borrow().get(&s2sym("_proto")) {
proto.proto_lookup(key)
} else {
None
}
},
VVal::Lst(l) => {
let l = l.borrow();
if l.is_empty() {
None
} else {
l[0].proto_lookup(key)
}
},
v => v.with_deref(|v| v.proto_lookup(key), |_| None),
}
}
pub fn get_key_sym(&self, key: &Symbol) -> Option<VVal> {
match self {
VVal::Map(m) => m.borrow().get(key).cloned(),
_ => self.get_key(key.as_ref()),
}
}
pub fn get_key(&self, key: &str) -> Option<VVal> {
match self {
VVal::Map(m) => m.borrow().get(&s2sym(key)).cloned(),
VVal::IVec(b) => {
Some(match key {
"0" | "first" | "x" | "r" | "h" => b.x(),
"1" | "second" | "y" | "g" | "s" => b.y(),
"2" | "third" | "z" | "b" | "v" => b.z().unwrap_or(VVal::None),
"3" | "fourth" | "w" | "a" => b.w().unwrap_or(VVal::None),
_ =>
swizzle_i(
key,
b.x_raw(),
b.y_raw(),
b.z_raw().unwrap_or(0),
b.w_raw().unwrap_or(0)),
})
},
VVal::FVec(b) => {
Some(match key {
"0" | "first" | "x" | "r" | "h" => b.x(),
"1" | "second" | "y" | "g" | "s" => b.y(),
"2" | "third" | "z" | "b" | "v" => b.z().unwrap_or(VVal::None),
"3" | "fourth" | "w" | "a" => b.w().unwrap_or(VVal::None),
_ =>
swizzle_f(
key,
b.x_raw(),
b.y_raw(),
b.z_raw().unwrap_or(0.0),
b.w_raw().unwrap_or(0.0)),
})
},
VVal::Pair(_) => {
self.at(match key {
"0" | "value" | "v" | "car" | "head" | "first" => 0,
"1" | "key" | "k" | "cdr" | "tail" | "second" => 1,
_ => {
if !key.chars().all(|c| c.is_digit(10)) { return None; }
usize::from_str_radix(key, 10).unwrap_or(0)
}
})
},
VVal::Iter(i) => {
if !key.chars().all(|c| c.is_digit(10)) { return None; }
let index = usize::from_str_radix(key, 10).unwrap_or(0);
let mut i = i.borrow_mut();
for _ in 0..index { i.next(); }
iter_next_value!(i, v, { Some(v) }, None)
},
VVal::Lst(l) => {
if !key.chars().all(|c| c.is_digit(10)) { return None; }
let idx = usize::from_str_radix(key, 10).unwrap_or(0);
if idx < l.borrow().len() {
Some(l.borrow()[idx].clone())
} else {
Some(VVal::None)
}
},
VVal::Usr(u) => u.get_key(key),
v => v.with_deref(|v| v.get_key(key), |_| None),
}
}
pub fn set_map_key_fun<T>(&self, key: &str, fun: T, min_args: Option<usize>, max_args: Option<usize>, err_arg_ok: bool)
where T: 'static + Fn(&mut Env, usize) -> Result<VVal, StackAction> {
self.set_key_sym(
s2sym(key),
VValFun::new_fun(fun, min_args, max_args, err_arg_ok))
.expect("Map not borrowed when using set_map_key_fun");
}
pub fn deref(&self) -> VVal {
self.with_deref(
|v| v.clone(),
|v| v.map_or(VVal::None, |v| v.clone()))
}
#[inline]
pub fn with_deref<O, D, R>(&self, op: O, default: D) -> R
where O: FnOnce(&VVal) -> R, D: FnOnce(Option<&VVal>) -> R
{
match self {
VVal::Opt(Some(v)) => op(v.as_ref()),
VVal::Opt(None) => op(&VVal::None),
VVal::Ref(l) => op(&(*l).borrow()),
VVal::HRef(l) => op(&(*l).borrow()),
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => op(&v.borrow()),
None => default(None),
}
},
_ => default(Some(self)),
}
}
pub fn list_operation<O, R>(&self, mut op: O) -> Result<R, StackAction>
where O: FnMut(&mut std::cell::RefMut<std::vec::Vec<VVal>>) -> R
{
match self {
VVal::Lst(l) => {
match l.try_borrow_mut() {
Ok(mut v) => { Ok(op(&mut v)) },
Err(_) => Err(StackAction::panic_borrow(self)),
}
},
v => v.with_deref(|v| {
v.list_operation(op)
}, |v| Err(StackAction::panic_msg(format!(
"Can't do list operation with non list value: {}",
v.map_or("".to_string(), |v| v.s())))))
}
}
pub fn delete_key(&self, key: &VVal) -> Result<VVal, StackAction> {
match self {
VVal::Map(m) => {
let ks = key.to_sym();
match m.try_borrow_mut() {
Ok(mut r) => Ok(r.remove(&ks).unwrap_or_else(|| VVal::None)),
Err(_) => Err(StackAction::panic_borrow(self)),
}
},
VVal::Lst(l) => {
let idx = key.i() as usize;
match l.try_borrow_mut() {
Ok(mut v) => {
if idx < v.len() {
Ok(v.remove(idx))
} else {
Ok(VVal::None)
}
},
Err(_) => Err(StackAction::panic_borrow(self)),
}
},
VVal::Usr(u) => u.delete_key(key),
v => v.with_deref(
|v| v.delete_key(key),
|_| Ok(VVal::None)),
}
}
pub fn set_key_str(&self, key: &str, val: VVal) -> Result<(), StackAction> {
self.set_key_sym(s2sym(key), val)
}
pub fn set_key_sym(&self, key: Symbol, val: VVal) -> Result<(), StackAction> {
match self {
VVal::Map(m) => {
match m.try_borrow_mut() {
Ok(mut r) => { r.insert(key, val); Ok(()) },
Err(_) => Err(StackAction::panic_borrow(self)),
}
},
_ => self.set_key(&VVal::Sym(key), val),
}
}
pub fn set_key(&self, key: &VVal, val: VVal) -> Result<(), StackAction> {
match self {
VVal::Map(m) => {
let ks = key.to_sym();
match m.try_borrow_mut() {
Ok(mut r) => { r.insert(ks, val); Ok(()) },
Err(_) => Err(StackAction::panic_borrow(self)),
}
},
VVal::Lst(l) => {
let idx = key.i() as usize;
match l.try_borrow_mut() {
Ok(mut v) => {
if v.len() <= idx {
v.resize(idx + 1, VVal::None);
}
v[idx] = val;
Ok(())
},
Err(_) => Err(StackAction::panic_borrow(self)),
}
},
VVal::FVec(_) =>
Err(StackAction::panic_msg(
"Can't mutate float vector".to_string())),
VVal::IVec(_) =>
Err(StackAction::panic_msg(
"Can't mutate integer vector".to_string())),
VVal::Pair(_) =>
Err(StackAction::panic_msg(
"Can't mutate pair".to_string())),
VVal::Usr(u) => u.set_key(key, val),
v => v.with_deref(
|v| v.set_key(key, val),
|_| Ok(())),
}
}
pub fn pop(&self) -> VVal {
if let VVal::Lst(b) = &self {
b.borrow_mut().pop().unwrap_or(VVal::None)
} else {
self.with_deref(|v| v.pop(), |_| VVal::None)
}
}
pub fn accum(&mut self, val: &VVal) {
match self {
VVal::Byt(ref mut b) => {
match val {
VVal::Int(i) => { Rc::make_mut(b).push(*i as u8); },
VVal::Flt(f) => { Rc::make_mut(b).push(*f as u8); },
VVal::Str(s) => { Rc::make_mut(b).extend_from_slice(s.as_bytes()); },
VVal::Sym(s) => { Rc::make_mut(b).extend_from_slice(s.as_bytes()); },
VVal::Byt(s) => { Rc::make_mut(b).extend_from_slice(s.as_ref()); },
VVal::Bol(o) => { Rc::make_mut(b).push(*o as u8); },
_ => {
val.with_bv_ref(
|s: &[u8]| Rc::make_mut(b).extend_from_slice(s));
}
}
},
VVal::Str(ref mut a) => {
match val {
VVal::Str(s) => { Rc::make_mut(a).push_str(s.as_ref()); },
VVal::Sym(s) => { Rc::make_mut(a).push_str(&*s); },
VVal::Byt(s) => {
for b in s.as_ref().iter() {
let b = *b as char;
Rc::make_mut(a).push(b);
}
},
_ => {
val.with_s_ref(|s: &str|
Rc::make_mut(a).push_str(s));
}
}
},
VVal::Int(i) => { *i += val.i(); },
VVal::Flt(f) => { *f += val.f(); },
VVal::Lst(v) => { v.borrow_mut().push(val.clone()); },
_ => (),
}
}
pub fn push(&self, val: VVal) -> &VVal {
if let VVal::Lst(b) = &self {
b.borrow_mut().push(val);
} else {
self.with_deref(|v| { v.push(val); }, |_| ())
}
self
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn len(&self) -> usize {
match self {
VVal::Chr(_) => 1,
VVal::Lst(l) => l.borrow().len(),
VVal::Map(l) => l.borrow().len(),
VVal::Byt(l) => l.len(),
VVal::Str(l) => l.len(),
VVal::Sym(l) => l.len(),
v => v.with_deref(|v| v.len(), |_| 0),
}
}
pub fn s_len(&self) -> usize {
match self {
VVal::Chr(_) => 1,
VVal::Str(s) => s.chars().count(),
VVal::Sym(s) => s.chars().count(),
VVal::Usr(s) => s.s_raw().chars().count(),
VVal::Byt(b) => b.len(),
VVal::None => 0,
_ => self.s().chars().count(),
}
}
pub fn s_raw(&self) -> String {
match self {
VVal::Chr(c) => {
let mut buf = [0; 6];
let chrstr = c.c().encode_utf8(&mut buf);
chrstr.to_string()
},
VVal::Str(s) => s.as_ref().clone(),
VVal::Sym(s) => String::from(s.as_ref()),
VVal::Usr(s) => s.s_raw(),
VVal::Byt(s) => s.iter().map(|b| *b as char).collect(),
VVal::None => String::from(""),
v => v.with_deref(|v| {
if v.is_none() { "".to_string() }
else { v.s_raw() }
}, |v| {
v.map_or_else(
|| "".to_string(),
|v| if v.is_none() { "".to_string() }
else { v.s() })
}),
}
}
#[inline]
pub fn with_s_ref<T, R>(&self, f: T) -> R
where T: FnOnce(&str) -> R
{
match self {
VVal::Chr(c) => {
let mut buf = [0; 6];
let chrstr = c.c().encode_utf8(&mut buf);
f(chrstr)
},
VVal::Str(s) => f(s.as_ref()),
VVal::Sym(s) => f(&*s),
VVal::Usr(s) => f(&s.s_raw()),
VVal::Byt(_) => f(&self.s_raw()),
VVal::None => f(""),
_ => f(&self.s_raw()),
}
}
#[inline]
pub fn with_bv_ref<T, R>(&self, f: T) -> R
where T: FnOnce(&[u8]) -> R
{
match self {
VVal::Chr(c) => f(&[c.byte()]),
VVal::Byt(v) => f(&v.as_ref()[..]),
VVal::Str(_) => {
self.with_s_ref(|s| f(s.as_bytes()))
},
_ => {
let vec = self.as_bytes();
f(&vec[..])
}
}
}
pub fn is_float(&self) -> bool {
match self { VVal::Flt(_) => true, _ => false }
}
pub fn is_int(&self) -> bool {
match self { VVal::Int(_) => true, _ => false }
}
pub fn is_char(&self) -> bool {
match self { VVal::Chr(VValChr::Char(_)) => true, _ => false }
}
pub fn is_byte(&self) -> bool {
match self { VVal::Chr(VValChr::Byte(_)) => true, _ => false }
}
pub fn is_sym(&self) -> bool {
match self { VVal::Sym(_) => true, _ => false }
}
pub fn is_syn(&self) -> bool {
match self { VVal::Syn(_) => true, _ => false }
}
pub fn get_syn_pos(&self) -> SynPos {
if let VVal::Syn(s) = self {
s.clone()
} else {
SynPos::empty()
}
}
pub fn syn(&self) -> Option<Syntax> {
if let VVal::Syn(s) = self {
Some(s.syn())
} else {
None
}
}
pub fn set_syn(&mut self, syn: Syntax) {
if let VVal::Syn(s) = self {
s.set_syn(syn);
}
}
pub fn set_syn_at(&self, idx: usize, syn: Syntax) {
let mut v = self.v_(idx);
v.set_syn(syn);
self.set(idx, v);
}
pub fn get_syn(&self) -> Syntax {
if let VVal::Syn(s) = self {
s.syn()
} else {
Syntax::Block
}
}
pub fn compile_err(&self, msg: String) -> CompileError {
CompileError {
msg,
pos: self.at(0).unwrap_or(VVal::None).get_syn_pos(),
}
}
pub fn to_compile_err(&self, msg: String) -> Result<EvalNode, CompileError> {
Err(self.compile_err(msg))
}
pub fn is_pair(&self) -> bool {
match self { VVal::Pair(_) => true, _ => false }
}
pub fn is_iter(&self) -> bool {
if let VVal::Iter(_) = self { true } else { false }
}
pub fn is_optional(&self) -> bool {
if let VVal::Opt(_) = self { true } else { false }
}
pub fn is_ref(&self) -> bool {
match self { VVal::Ref(_) => true, VVal::HRef(_) => true, VVal::WWRef(_) => true, _ => false }
}
pub fn is_wref(&self) -> bool {
match self { VVal::WWRef(_) => true, _ => false }
}
pub fn is_bool(&self) -> bool {
match self { VVal::Bol(_) => true, _ => false }
}
pub fn is_bytes(&self) -> bool {
match self { VVal::Byt(_) => true, _ => false }
}
pub fn is_str(&self) -> bool {
match self { VVal::Str(_) => true, _ => false }
}
pub fn is_fun(&self) -> bool {
match self { VVal::Fun(_) => true, _ => false }
}
pub fn is_vec(&self) -> bool {
match self { VVal::Lst(_) => true, _ => false }
}
pub fn is_nvec(&self) -> bool {
match self { VVal::FVec(_) => true, VVal::IVec(_) => true, _ => false }
}
pub fn is_ivec(&self) -> bool {
match self { VVal::IVec(_) => true, _ => false }
}
pub fn is_fvec(&self) -> bool {
match self { VVal::FVec(_) => true, _ => false }
}
pub fn nvec_len(&self) -> usize {
match self {
VVal::IVec(nv) => nv.dims().len(),
VVal::FVec(nv) => nv.dims().len(),
_ => 0,
}
}
pub fn is_map(&self) -> bool {
match self { VVal::Map(_) => true, _ => false }
}
pub fn is_some(&self) -> bool {
match self {
VVal::None => false,
VVal::Opt(None) => false,
_ => true
}
}
pub fn is_none(&self) -> bool {
match self {
VVal::None => true,
VVal::Opt(None) => true,
_ => false,
}
}
pub fn is_err(&self) -> bool {
match self { VVal::Err(_) => true, _ => false }
}
pub fn type_name(&self) -> &str {
match self {
VVal::Str(_) => "string",
VVal::Byt(_) => "bytes",
VVal::Chr(VValChr::Char(_)) => "char",
VVal::Chr(VValChr::Byte(_)) => "byte",
VVal::None => "none",
VVal::Err(_) => "error",
VVal::Bol(_) => "bool",
VVal::Sym(_) => "symbol",
VVal::Syn(_) => "syntax",
VVal::Int(_) => "integer",
VVal::Flt(_) => "float",
VVal::Pair(_) => "pair",
VVal::Iter(_) => "iter",
VVal::Opt(_) => "optional",
VVal::Lst(_) => "vector",
VVal::Map(_) => "map",
VVal::Usr(_) => "userdata",
VVal::Fun(_) => "function",
VVal::IVec(_) => "integer_vector",
VVal::FVec(_) => "float_vector",
VVal::DropFun(_) => "drop_function",
VVal::Ref(_) => "ref_strong",
VVal::HRef(_) => "ref_hidden",
VVal::WWRef(_) => "ref_weak",
}
}
pub fn with_usr_ref<T: 'static, F, X>(&mut self, f: F) -> Option<X>
where F: FnOnce(&mut T) -> X {
if let VVal::Usr(bx) = self {
if let Some(ud) = bx.as_any().downcast_mut::<T>() {
Some(f(ud))
} else {
None
}
} else {
None
}
}
pub fn v_(&self, idx: usize) -> VVal { self.at(idx).unwrap_or_else(|| VVal::None) }
pub fn v_k(&self, key: &str) -> VVal { self.get_key(key).unwrap_or(VVal::None) }
pub fn v_i(&self, idx: usize) -> i64 { self.v_(idx).i() }
pub fn v_ik(&self, key: &str) -> i64 { self.v_k(key).i() }
pub fn v_c(&self, idx: usize) -> char { self.v_(idx).c() }
pub fn v_ck(&self, key: &str) -> char { self.v_k(key).c() }
pub fn v_byte(&self, idx: usize) -> u8 { self.v_(idx).byte() }
pub fn v_bytek(&self, key: &str) -> u8 { self.v_k(key).byte() }
pub fn v_s_raw(&self, idx: usize) -> String { self.v_(idx).s_raw() }
pub fn v_with_s_ref<T, R>(&self, idx: usize, f: T) -> R
where T: FnOnce(&str) -> R
{
self.v_(idx).with_s_ref(f)
}
pub fn v_s_rawk(&self, key: &str) -> String { self.v_k(key).s_raw() }
pub fn v_with_s_refk<T, R>(&self, key: &str, f: T) -> R
where T: FnOnce(&str) -> R
{
self.v_k(key).with_s_ref(f)
}
pub fn v_s(&self, idx: usize) -> String { self.v_(idx).s() }
pub fn v_sk(&self, key: &str) -> String { self.v_k(key).s() }
pub fn v_f(&self, idx: usize) -> f64 { self.v_(idx).f() }
pub fn v_fk(&self, key: &str) -> f64 { self.v_k(key).f() }
pub fn for_each<T>(&self, mut op: T)
where T: FnMut(&VVal) -> () {
if let VVal::Lst(b) = &self {
for i in b.borrow().iter() { op(i); }
}
}
pub fn for_eachk<T>(&self, mut op: T)
where T: FnMut(&str, &VVal) -> () {
if let VVal::Map(b) = &self {
for (k, v) in b.borrow().iter() { op(&k, v); }
}
}
#[allow(clippy::cast_lossless)]
pub fn f(&self) -> f64 {
match self {
VVal::Str(s) => (*s).parse::<f64>().unwrap_or(0.0),
VVal::Sym(s) => (*s).parse::<f64>().unwrap_or(0.0),
VVal::Byt(s) => if s.len() > 0 { s[0] as f64 } else { 0.0 },
VVal::Chr(c) => c.c() as u32 as f64,
VVal::None => 0.0,
VVal::Err(_) => 0.0,
VVal::Bol(b) => if *b { 1.0 } else { 0.0 },
VVal::Syn(s) => (s.syn() as i64) as f64,
VVal::Int(i) => *i as f64,
VVal::Flt(f) => *f,
VVal::Pair(b) => b.0.f(),
VVal::Lst(l) => l.borrow().len() as f64,
VVal::Map(l) => l.borrow().len() as f64,
VVal::Usr(u) => u.f(),
VVal::Fun(_) => 1.0,
VVal::IVec(iv) => iv.x_raw() as f64,
VVal::FVec(fv) => fv.x_raw(),
VVal::Iter(i) => iter_next_value!(i.borrow_mut(), v, { v.f() }, 0.0),
v => v.with_deref(|v| v.f(), |_| 0.0),
}
}
#[allow(clippy::cast_lossless)]
pub fn i(&self) -> i64 {
match self {
VVal::Str(s) => (*s).parse::<i64>().unwrap_or(0),
VVal::Sym(s) => (*s).parse::<i64>().unwrap_or(0),
VVal::Chr(c) => c.c() as u32 as i64,
VVal::Byt(s) => if s.len() > 0 { s[0] as i64 } else { 0 as i64 },
VVal::None => 0,
VVal::Err(_) => 0,
VVal::Bol(b) => if *b { 1 } else { 0 },
VVal::Syn(s) => s.syn() as i64,
VVal::Int(i) => *i,
VVal::Flt(f) => (*f as i64),
VVal::Pair(b) => b.0.i(),
VVal::Lst(l) => l.borrow().len() as i64,
VVal::Map(l) => l.borrow().len() as i64,
VVal::Usr(u) => u.i(),
VVal::Fun(_) => 1,
VVal::IVec(iv) => iv.x_raw(),
VVal::FVec(fv) => fv.x_raw() as i64,
VVal::Iter(i) => iter_next_value!(i.borrow_mut(), v, { v.i() }, 0),
v => v.with_deref(|v| v.i(), |_| 0),
}
}
#[allow(clippy::cast_lossless)]
pub fn byte(&self) -> u8 {
match self {
VVal::Str(s) => { if (*s).len() > 0 { (*s).as_bytes()[0] } else { 0 } },
VVal::Sym(s) => { if (*s).len() > 0 { (*s).as_bytes()[0] } else { 0 } },
VVal::Chr(c) => c.byte(),
VVal::Byt(s) => if s.len() > 0 { s[0] } else { b'0' },
VVal::None => b'\0',
VVal::Err(_) => b'\0',
VVal::Bol(b) => if *b { b'\x01' } else { b'\0' },
VVal::Syn(s) => s.syn() as i64 as u32 as u8,
VVal::Int(i) => if *i <= 255 { *i as u8 } else { b'?' as u8 },
VVal::Flt(f) => if (*f as u32) <= 255 { *f as u8 } else { b'?' as u8 },
VVal::Pair(b) => b.0.byte(),
VVal::Lst(l) => l.borrow().len() as u8,
VVal::Map(l) => l.borrow().len() as u8,
VVal::Usr(u) => u.byte(),
VVal::Fun(_) => b'\x01',
VVal::IVec(iv) => iv.x_raw() as u8,
VVal::FVec(fv) => fv.x_raw() as u8,
VVal::Iter(i) => iter_next_value!(i.borrow_mut(), v, { v.byte() }, b'\0'),
v => v.with_deref(|v| v.byte(), |_| b'\0'),
}
}
#[allow(clippy::cast_lossless)]
pub fn c(&self) -> char {
match self {
VVal::Str(s) => (*s).chars().nth(0).unwrap_or('\0'),
VVal::Sym(s) => (*s).chars().nth(0).unwrap_or('\0'),
VVal::Chr(c) => c.c(),
VVal::Byt(s) => if s.len() > 0 { s[0] as char } else { '\0' },
VVal::None => '\0',
VVal::Err(_) => '\0',
VVal::Bol(b) => if *b { '\u{01}' } else { '\0' },
VVal::Syn(s) => std::char::from_u32(s.syn() as i64 as u32).unwrap_or('\0'),
VVal::Int(i) => std::char::from_u32(*i as u32).unwrap_or('\0'),
VVal::Flt(f) => std::char::from_u32(*f as u32).unwrap_or('\0'),
VVal::Pair(b) => b.0.c(),
VVal::Lst(l) => std::char::from_u32(l.borrow().len() as u32).unwrap_or('\0'),
VVal::Map(l) => std::char::from_u32(l.borrow().len() as u32).unwrap_or('\0'),
VVal::Usr(u) => u.c(),
VVal::Fun(_) => '\u{01}',
VVal::IVec(iv) => std::char::from_u32(iv.x_raw() as u32).unwrap_or('\0'),
VVal::FVec(fv) => std::char::from_u32(fv.x_raw() as u32).unwrap_or('\0'),
VVal::Iter(i) => iter_next_value!(i.borrow_mut(), v, { v.c() }, '\0'),
v => v.with_deref(|v| v.c(), |_| '\0'),
}
}
#[allow(clippy::cast_lossless)]
pub fn b(&self) -> bool {
match self {
VVal::Str(s) => (*s).parse::<i64>().unwrap_or(0) != 0,
VVal::Sym(s) => (*s).parse::<i64>().unwrap_or(0) != 0,
VVal::Chr(c) => (c.c() as u32) > 0,
VVal::Byt(s) => (if s.len() > 0 { s[0] as i64 } else { 0 as i64 }) != 0,
VVal::None => false,
VVal::Err(_) => false,
VVal::Bol(b) => *b,
VVal::Syn(s) => (s.syn() as i64) != 0,
VVal::Pair(b) => b.0.b() || b.1.b(),
VVal::Int(i) => (*i) != 0,
VVal::Flt(f) => (*f as i64) != 0,
VVal::Lst(l) => (l.borrow().len() as i64) != 0,
VVal::Map(l) => (l.borrow().len() as i64) != 0,
VVal::Usr(u) => u.b(),
VVal::Fun(_) => true,
VVal::Opt(None) => false,
VVal::Opt(Some(_)) => true,
VVal::IVec(iv) => iv.x().b(),
VVal::FVec(fv) => fv.x().b(),
VVal::Iter(i) => iter_next_value!(i.borrow_mut(), v, { v.b() }, false),
v => v.with_deref(|v| v.b(), |_| false),
}
}
pub fn nvec<N: crate::nvec::NVecNum>(&self) -> NVec<N> {
use NVec::*;
match self {
VVal::IVec(i) => N::from_ivec(**i),
VVal::FVec(f) => N::from_fvec(**f),
VVal::Map(map) => {
let m = map.borrow();
let o = N::zero().into_vval();
NVec::from_vval_tpl(
(m.get(&s2sym("x")).unwrap_or(&o),
m.get(&s2sym("y")).unwrap_or(&o),
m.get(&s2sym("z")),
m.get(&s2sym("w")))
).unwrap_or_else(|| {
NVec::from_vval_tpl(
(m.get(&s2sym("x")).unwrap_or(&o),
m.get(&s2sym("y")).unwrap_or(&o),
Some(&o),
m.get(&s2sym("w")))
).unwrap()
})
},
VVal::Lst(lst) => {
let list = lst.borrow();
let mut lst = list.iter();
let zero = N::zero().into_vval();
let (x, y, z, w) = (lst.next(), lst.next(), lst.next(), lst.next());
NVec::from_vval_tpl(
(x.unwrap_or(&zero), y.unwrap_or(&zero), z, w))
.unwrap()
},
VVal::Pair(p) => {
NVec::from_vval_tpl((p.0.clone(), p.1.clone(), None, None)).unwrap()
},
VVal::Iter(i) => {
iter_next_value!(
i.borrow_mut(), v, { v.nvec::<N>() },
NVec::from_vval_tpl(
(VVal::Int(0), VVal::Int(0), None, None)).unwrap())
},
_ => Vec2(N::from_vval(self), N::zero()),
}
}
fn s_cy(&self, c: &mut CycleCheck) -> String {
let br = if let Some((do_continue, backref_str)) = c.backref(self) {
if !do_continue { return backref_str; }
backref_str
} else {
String::from("")
};
let s = match self {
VVal::Str(_) => self.with_s_ref(|s| format_vval_str(s, false)),
VVal::Sym(s) => VVal::dump_sym(&*s),
VVal::Byt(s) => format!("$b{}", format_vval_byt(s.as_ref())),
VVal::None => "$n".to_string(),
VVal::Err(e) => format!("$e{} {}", (*e).borrow().1, (*e).borrow().0.s_cy(c)),
VVal::Bol(b) => if *b { "$true".to_string() } else { "$false".to_string() },
VVal::Syn(s) => format!("&{:?}", s.syn()),
VVal::Chr(c) => c.to_string(),
VVal::Int(i) => i.to_string(),
VVal::Flt(f) => f.to_string(),
VVal::Pair(b) => format!("$p({},{})", b.0.s_cy(c), b.1.s_cy(c)),
VVal::Iter(_) => "$iter(&)".to_string(),
VVal::Opt(b) =>
if let Some(b) = b { format!("$o({})", b.s_cy(c)) }
else { "$o()".to_string() },
VVal::Lst(l) => VVal::dump_vec_as_str(l, c),
VVal::Map(l) => VVal::dump_map_as_str(l, c), VVal::Usr(u) => u.s(),
VVal::Fun(f) => {
let min = if f.min_args.is_none() { "any".to_string() }
else { format!("{}", f.min_args.unwrap()) };
let max = if f.max_args.is_none() { "any".to_string() }
else { format!("{}", f.max_args.unwrap()) };
let upvalues : String =
f.upvalues
.iter()
.map(|v| v.s_cy(c))
.collect::<Vec<String>>()
.join(",");
if let Some(ref sp) = f.syn_pos {
format!("&F{{@{},amin={},amax={},locals={},upvalues=$[{}]}}",
sp, min, max, f.local_size, upvalues)
} else {
format!("&F{{@[0,0:?()],amin={},amax={},locals={},upvalues=$[{}]}}",
min, max, f.local_size, upvalues)
}
},
VVal::DropFun(f) => format!("std:to_drop[{}]", f.fun.s_cy(c)),
VVal::Ref(l) => format!("$&&{}", (*l).borrow().s_cy(c)),
VVal::HRef(l) => format!("$&{}", (*l).borrow().s_cy(c)),
VVal::FVec(nvec) => nvec.s(),
VVal::IVec(nvec) => nvec.s(),
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => format!("$w&{}", v.borrow().s_cy(c)),
None => "$n".to_string(),
}
},
};
format!("{}{}", br, s)
}
pub fn as_bytes(&self) -> std::vec::Vec<u8> {
match self {
VVal::Chr(c) => vec![c.byte()],
VVal::Byt(b) => b.as_ref().clone(),
v => v.with_deref(
|v| v.as_bytes(),
|v| v.map_or_else(
|| vec![],
|v| v.with_s_ref(|s: &str| s.as_bytes().to_vec()))),
}
}
pub fn to_duration(&self) -> Result<std::time::Duration, VVal> {
match self {
VVal::Int(i) => Ok(std::time::Duration::from_millis(*i as u64)),
VVal::Pair(b) => {
let a = &b.0;
let b = &b.1;
a.with_s_ref(|astr|
match astr {
"s" => Ok(std::time::Duration::from_secs(b.i() as u64)),
"ms" => Ok(std::time::Duration::from_millis(b.i() as u64)),
"us" => Ok(std::time::Duration::from_micros(b.i() as u64)),
"ns" => Ok(std::time::Duration::from_nanos(b.i() as u64)),
_ => Err(VVal::err_msg(&format!("Bad duration: {}", self.s()))),
})
},
_ => Err(VVal::err_msg(&format!("Bad duration: {}", self.s()))),
}
}
pub fn s(&self) -> String {
let mut cc = CycleCheck::new();
cc.touch_walk(self);
self.s_cy(&mut cc)
}
#[cfg(feature="rmp-serde")]
pub fn to_msgpack(&self) -> Result<Vec<u8>, String> {
match rmp_serde::to_vec(self) {
Ok(s) => Ok(s),
Err(e) => Err(format!("to_msgpack failed: {}", e))
}
}
#[cfg(feature="rmp-serde")]
pub fn from_msgpack(s: &[u8]) -> Result<VVal, String> {
match rmp_serde::from_read_ref(&s) {
Ok(v) => Ok(v),
Err(e) => Err(format!("from_msgpack failed: {}", e)),
}
}
#[cfg(feature="serde_json")]
pub fn to_json(&self, not_pretty: bool) -> Result<String, String> {
if not_pretty {
match serde_json::to_string(self) {
Ok(s) => Ok(s),
Err(e) => Err(format!("to_json failed: {}", e))
}
} else {
match serde_json::to_string_pretty(self) {
Ok(s) => Ok(s),
Err(e) => Err(format!("to_json failed: {}", e))
}
}
}
#[cfg(feature="serde_json")]
pub fn from_json(s: &str) -> Result<VVal, String> {
match serde_json::from_str(&s) {
Ok(v) => Ok(v),
Err(e) => Err(format!("from_json failed: {}", e)),
}
}
}
#[cfg(feature="serde")]
impl serde::ser::Serialize for VVal {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::ser::Serializer {
use serde::ser::{SerializeSeq, SerializeMap};
match self {
VVal::Str(_) => self.with_s_ref(|s: &str| serializer.serialize_str(s)),
VVal::Sym(_) => self.with_s_ref(|s: &str| serializer.serialize_str(s)),
VVal::Byt(b) => serializer.serialize_bytes(&b[..]),
VVal::Chr(b) =>
match b {
VValChr::Char(c) => {
let mut buf = [0; 6];
serializer.serialize_str(c.encode_utf8(&mut buf))
},
VValChr::Byte(b) => { serializer.serialize_u8(*b) },
},
VVal::None => serializer.serialize_none(),
VVal::Iter(_) => serializer.serialize_none(),
VVal::Err(_) => serializer.serialize_str(&self.s()),
VVal::Bol(b) => serializer.serialize_bool(*b),
VVal::Syn(_) => serializer.serialize_str(&self.s()),
VVal::Int(i) => serializer.serialize_i64(*i),
VVal::Flt(f) => serializer.serialize_f64(*f),
VVal::Pair(b) => {
let mut seq = serializer.serialize_seq(Some(2))?;
seq.serialize_element(&b.0)?;
seq.serialize_element(&b.1)?;
seq.end()
},
VVal::Opt(b) => {
if let Some(b) = b {
let mut seq = serializer.serialize_seq(Some(1))?;
seq.serialize_element(b.as_ref())?;
seq.end()
} else {
let seq = serializer.serialize_seq(Some(0))?;
seq.end()
}
},
VVal::Lst(l) => {
let mut seq = serializer.serialize_seq(Some(l.borrow().len()))?;
for v in l.borrow().iter() {
seq.serialize_element(v)?;
}
seq.end()
},
VVal::Map(l) => {
let hm = l.borrow();
let mut map = serializer.serialize_map(Some(l.borrow().len()))?;
for (k, v) in hm.iter() {
map.serialize_entry(k.as_ref(), v)?;
}
map.end()
},
VVal::Usr(_) => serializer.serialize_str(&self.s()),
VVal::Fun(_) => serializer.serialize_str(&self.s()),
VVal::FVec(fv) => {
match fv.as_ref() {
NVec::Vec2(x, y) => {
let mut seq = serializer.serialize_seq(Some(2))?;
seq.serialize_element(x)?;
seq.serialize_element(y)?;
seq.end()
},
NVec::Vec3(x, y, z) => {
let mut seq = serializer.serialize_seq(Some(3))?;
seq.serialize_element(x)?;
seq.serialize_element(y)?;
seq.serialize_element(z)?;
seq.end()
},
NVec::Vec4(x, y, z, w) => {
let mut seq = serializer.serialize_seq(Some(4))?;
seq.serialize_element(x)?;
seq.serialize_element(y)?;
seq.serialize_element(z)?;
seq.serialize_element(w)?;
seq.end()
},
}
},
VVal::IVec(iv) => {
match iv.as_ref() {
NVec::Vec2(x, y) => {
let mut seq = serializer.serialize_seq(Some(2))?;
seq.serialize_element(x)?;
seq.serialize_element(y)?;
seq.end()
},
NVec::Vec3(x, y, z) => {
let mut seq = serializer.serialize_seq(Some(3))?;
seq.serialize_element(x)?;
seq.serialize_element(y)?;
seq.serialize_element(z)?;
seq.end()
},
NVec::Vec4(x, y, z, w) => {
let mut seq = serializer.serialize_seq(Some(4))?;
seq.serialize_element(x)?;
seq.serialize_element(y)?;
seq.serialize_element(z)?;
seq.serialize_element(w)?;
seq.end()
},
}
},
VVal::DropFun(_) => serializer.serialize_str(&self.s()),
VVal::Ref(_) => self.deref().serialize(serializer),
VVal::HRef(_) => self.deref().serialize(serializer),
VVal::WWRef(_) => self.deref().serialize(serializer),
}
}
}
#[cfg(feature="serde")]
struct VValVisitor;
#[cfg(feature="serde")]
impl<'de> serde::de::Visitor<'de> for VValVisitor {
type Value = VVal;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a VVal")
}
fn visit_i128<E>(self, value: i128) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(value as i64)) }
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(value)) }
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(i64::from(value))) }
fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(i64::from(value))) }
fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(i64::from(value))) }
fn visit_u128<E>(self, value: u128) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(value as i64)) }
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(value as i64)) }
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(i64::from(value))) }
fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(i64::from(value))) }
fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Int(i64::from(value))) }
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Flt(value)) }
fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Flt(f64::from(value))) }
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Bol(value)) }
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::new_str(value)) }
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::new_byt(value.to_vec())) }
fn visit_none<E>(self) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::None) }
fn visit_unit<E>(self) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::None) }
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where A: serde::de::SeqAccess<'de> {
let v = VVal::vec();
while let Some(ve) = seq.next_element()? {
v.push(ve);
}
Ok(v)
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where A: serde::de::MapAccess<'de> {
let v = VVal::map();
while let Some((ke, ve)) = map.next_entry()? {
let k : VVal = ke;
v.set_key(&k, ve)
.expect("Deserialized map not used more than once");
}
Ok(v)
}
}
#[cfg(feature="serde")]
impl<'de> serde::de::Deserialize<'de> for VVal {
fn deserialize<D>(deserializer: D) -> Result<VVal, D::Error>
where D: serde::de::Deserializer<'de>,
{
deserializer.deserialize_any(VValVisitor)
}
}