use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::fmt;
use std::fmt::{Display, Debug, Formatter};
#[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 SynPos {
pub syn: Syntax,
pub line: u32,
pub col: u32,
pub file: FileRef,
}
impl Display for SynPos {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
if self.line > 0 {
write!(f, "[{},{}:{}({:?})]",
self.line, self.col, self.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.line, self.pos.col, self.pos.file, self.msg)
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub enum Syntax {
Var,
Key,
SetKey,
Str,
Lst,
Map,
Expr,
Func,
Block,
Err,
Call,
Apply,
And,
Or,
Assign,
Def,
Ref,
WRef,
Deref,
AssignRef,
DefGlobRef,
Import,
Export,
}
const STACK_SIZE : usize = 10240;
#[derive(Debug, Clone)]
pub struct Env {
pub args: std::vec::Vec<VVal>,
pub fun: Rc<VValFun>,
pub bp: usize,
pub sp: usize,
pub argc: usize,
pub user: Rc<RefCell<dyn std::any::Any>>,
pub exports: std::collections::HashMap<String, VVal>,
}
impl Default for Env {
fn default() -> Self { Self::new() }
}
impl Env {
pub fn new() -> Env {
let mut e = Env {
args: Vec::with_capacity(STACK_SIZE),
fun: VValFun::new_dummy(),
bp: 0,
sp: 0,
argc: 0,
user: Rc::new(RefCell::new(VVal::vec())),
exports: std::collections::HashMap::new(),
};
e.args.resize(STACK_SIZE, VVal::Nul);
e
}
pub fn new_with_user(user: Rc<RefCell<dyn std::any::Any>>) -> Env {
let mut e = Env {
args: Vec::with_capacity(STACK_SIZE),
fun: VValFun::new_dummy(),
bp: 0,
sp: 0,
argc: 0,
exports: std::collections::HashMap::new(),
user,
};
e.args.resize(STACK_SIZE, VVal::Nul);
e
}
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(String::from(name), value.clone());
}
pub fn set_bp(&mut self, env_size: usize) -> usize {
let new_bp = self.sp;
self.sp += env_size;
std::mem::replace(&mut self.bp, new_bp)
}
pub fn reset_bp(&mut self, env_size: usize, oldbp: usize) {
for i in self.bp..self.sp {
self.args[i] = VVal::Nul;
}
self.sp -= env_size;
self.bp = oldbp;
}
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
}
pub fn with_fun_info<T>(&mut self, fu: Rc<VValFun>, argc: usize, f: T) -> Result<VVal, StackAction>
where T: Fn(&mut Env) -> Result<VVal, StackAction> {
let local_size = fu.local_size;
let old_argc = std::mem::replace(&mut self.argc, argc);
let old_fun = std::mem::replace(&mut self.fun, fu);
let old_bp = self.set_bp(local_size);
let ret = f(self);
self.reset_bp(local_size, old_bp);
self.fun = old_fun;
self.argc = old_argc;
ret
}
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
}
pub fn with_pushed_sp<T>(&mut self, n: usize, f: T) -> Result<VVal, StackAction>
where T: Fn(&mut Env) -> Result<VVal, StackAction> {
self.push_sp(n);
let ret = f(self);
self.popn(n);
ret
}
pub fn push_sp(&mut self, n: usize) {
self.sp += n;
}
pub fn push(&mut self, v: VVal) -> usize {
self.args[self.sp] = v;
self.sp += 1;
self.sp - 1
}
pub fn popn(&mut self, n: usize) {
if self.sp < n {
panic!(format!("Stack pointer underflow {} {}", self.sp, n));
}
if n > 0 {
for i in (self.sp - 1)..=(self.sp - n) {
self.args[i] = VVal::Nul;
}
}
self.sp -= n;
}
pub fn dump_stack(&self) {
println!("* SP={}, BP={}", self.sp, self.bp);
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 >= self.sp { break; }
}
for (i, u) in self.fun.upvalues.iter().enumerate() {
println!(" UP[{:3}] = {}", i, u.s());
}
}
pub fn argv(&mut self) -> VVal {
VVal::vec_from(&self.args[(self.bp - self.argc)..self.bp])
}
pub fn get_up_raw(&mut self, i: usize) -> VVal {
self.fun.upvalues[i].clone()
}
pub fn get_up(&mut self, i: usize) -> VVal {
self.fun.upvalues[i].deref()
}
pub fn set_arg(&mut self, i: usize, v: VVal) {
self.args[self.sp - (i + 1)] = v;
}
pub fn arg_ref(&self, i: usize) -> Option<&VVal> {
if i >= self.argc { return None; }
Some(&self.args[self.bp - (i + 1)])
}
pub fn arg_err_internal(&self, i: usize) -> Option<VVal> {
let v = &self.args[self.bp - (i + 1)];
match v {
VVal::Err(_) => Some(v.clone()),
_ => None,
}
}
pub fn arg(&self, i: usize) -> VVal {
if i >= self.argc { return VVal::Nul; }
let v = &self.args[self.bp - (i + 1)];
match v {
VVal::DropFun(r) => r.v.clone(),
v => v.clone(),
}
}
pub fn get_local(&mut self, i: usize) -> VVal {
let idx = self.bp + i;
self.args[idx].clone()
}
pub fn set_up(&mut self, index: usize, value: &VVal) {
let fun = self.fun.clone();
let upv = &fun.upvalues[index];
match upv {
VVal::Ref(r) => { r.replace(value.clone()); }
VVal::CRef(r) => { r.replace(value.clone()); }
VVal::WWRef(r) => {
if let Some(r) = Weak::upgrade(r) {
r.replace(value.clone());
}
},
_ => {}
}
}
pub fn set_local(&mut self, i: usize, value: &VVal) {
let idx = self.bp + i;
self.args[idx] = value.clone();
}
pub fn set_consume(&mut self, i: usize, value: VVal) {
let idx = self.bp + i;
self.args[idx] = value;
}
}
#[derive(Clone)]
pub enum StackAction {
Panic(VVal, Vec<Option<SynPos>>),
Return((VVal, VVal)),
Break(VVal),
Next,
}
impl Display for StackAction {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
StackAction::Panic(v, spstk) => {
let stk : Vec<String> =
spstk.iter().map(|s|
if let Some(p) = s { format!("{}", p) }
else { String::from("[?]") })
.collect();
write!(f, "{} SA::Panic({})", stk.join("=>"), v.s())
},
StackAction::Return((l, v)) => write!(f, "SA::Return(lbl={},{})", l.s_raw(), v.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_msg(err: String) -> Self {
let v = Vec::new();
StackAction::Panic(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(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(err, v)
}
pub fn wrap_panic(self, sp: Option<SynPos>) -> Self {
match self {
StackAction::Panic(v, mut stk) => {
stk.push(sp);
StackAction::Panic(v, stk)
},
_ => self,
}
}
}
pub type EvalNode = Box<dyn Fn(&mut Env) -> Result<VVal,StackAction>>;
pub type ClosNodeRef = Rc<RefCell<dyn Fn(&mut Env, usize) -> Result<VVal,StackAction>>>;
pub struct VValFun {
pub fun: ClosNodeRef,
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>,
}
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)
}
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))
}
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>) -> VVal {
VVal::Fun(Rc::new(VValFun {
upvalues,
fun,
local_size: env_size,
min_args,
max_args,
err_arg_ok,
syn_pos,
}))
}
pub fn new_dummy() -> Rc<VValFun> {
Rc::new(VValFun {
fun: Rc::new(RefCell::new(|_: &mut Env, _a: usize| { Ok(VVal::Nul) })),
upvalues: Vec::new(),
local_size: 0,
min_args: None,
max_args: None,
err_arg_ok: false,
syn_pos: None,
})
}
pub fn dump_upvals(&self) -> VVal {
let v = VVal::vec();
for uv in self.upvalues.iter() {
v.push(VVal::new_str_mv(uv.s()));
}
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 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) { }
fn get_key(&self, _key: &str) -> Option<VVal> { None }
fn call(&self, _args: &[VVal]) -> Result<VVal, StackAction> { Ok(VVal::Nul) }
fn as_any(&mut self) -> &mut dyn std::any::Any;
}
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 DropVVal {
pub v: VVal,
pub fun: VVal,
}
impl Drop for DropVVal {
#[allow(unused_must_use)]
fn drop(&mut self) {
let mut e = Env::new();
e.push(self.v.clone());
self.fun.call_internal(&mut e, 1);
}
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum VVal {
Nul,
Err(Rc<RefCell<(VVal, SynPos)>>),
Bol(bool),
Sym(String),
Str(Rc<RefCell<String>>),
Byt(Rc<RefCell<Vec<u8>>>),
Int(i64),
Flt(f64),
Syn(SynPos),
Lst(Rc<RefCell<std::vec::Vec<VVal>>>),
Map(Rc<RefCell<std::collections::HashMap<String, VVal>>>),
Fun(Rc<VValFun>),
DropFun(Rc<DropVVal>),
Ref(Rc<RefCell<VVal>>),
CRef(Rc<RefCell<VVal>>),
WWRef(Weak<RefCell<VVal>>),
Usr(Box<dyn VValUserData>),
}
impl std::fmt::Debug for VValFun {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "&VValFun")
}
}
pub fn format_vval_str(s: &str, narrow_ascii: bool) -> String {
let mut v : Vec<String> = s.chars().map(|c| {
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) }
}
}).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: std::collections::HashMap<i64, i64>,
backref_counter: i64,
}
impl CycleCheck {
fn new() -> Self {
CycleCheck {
refs: std::collections::HashMap::new(),
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::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) => { self.touch_walk(&f.v); },
VVal::Fun(f) => {
for v in f.upvalues.iter() {
self.touch_walk(v);
}
},
VVal::Ref(l) => { self.touch_walk(&(*l).borrow()); },
VVal::CRef(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::Nul
| VVal::Bol(_)
| VVal::Sym(_)
| VVal::Syn(_)
| VVal::Int(_)
| VVal::Flt(_)
| VVal::Usr(_) => {},
}
}
fn touch(&mut self, v: &VVal) -> Option<i64> {
let id =
if let Some(id) = v.ref_id() { id }
else { return None; };
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)> {
let id =
if let Some(id) = v.ref_id() { id }
else { return None; };
if let Some(backref) = self.refs.get(&id) {
if *backref > 0 {
let i = *backref;
self.refs.insert(id, -i);
Some((true, format!("$<{}=>", i)))
} else if *backref < 0 {
Some((false, format!("$<{}>", -*backref)))
} else {
None
}
} else {
None
}
}
}
#[allow(dead_code)]
impl VVal {
pub fn new_str(s: &str) -> VVal {
VVal::Str(Rc::new(RefCell::new(String::from(s))))
}
pub fn new_str_mv(s: String) -> VVal {
VVal::Str(Rc::new(RefCell::new(s)))
}
pub fn new_sym(s: &str) -> VVal {
VVal::Sym(String::from(s))
}
pub fn new_byt(v: Vec<u8>) -> VVal {
VVal::Byt(Rc::new(RefCell::new(v)))
}
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 { syn: Syntax::Block, line: 0, col: 0, file: FileRef::new("?") }))))
}
pub fn vec() -> VVal {
VVal::Lst(Rc::new(RefCell::new(Vec::new())))
}
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);
v.reverse();
VVal::Lst(Rc::new(RefCell::new(v)))
}
pub fn vec_mv(v: Vec<VVal>) -> VVal {
VVal::Lst(Rc::new(RefCell::new(v)))
}
pub fn call(&self, env: &mut Env, args: &[VVal]) -> Result<VVal, StackAction> {
let argc = args.len();
env.with_pushed_sp(argc, |e: &mut Env| {
for (i, v) in args.iter().enumerate() {
e.set_arg(i, v.clone());
}
self.call_internal(e, argc)
})
}
pub fn call_no_args(&self, env: &mut Env) -> Result<VVal, StackAction> {
self.call_internal(env, 0)
}
pub fn call_internal(&self, env: &mut Env, argc: usize) -> Result<VVal, StackAction> {
match self {
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.with_fun_info(fu.clone(), argc, |e: &mut Env| {
if !(*fu).err_arg_ok {
for i in 0..argc {
if let Some(VVal::Err(ev)) = e.arg_err_internal(i) {
return
Err(StackAction::panic_str(
format!("Error value in parameter list: {}",
ev.borrow().0.s()),
Some(ev.borrow().1.clone())));
}
}
}
((*fu).fun.borrow())(e, argc)
})
},
VVal::Bol(b) => {
env.with_local_call_info(argc, |e: &mut Env| {
let idx = if *b { 0 } else { 1 };
if argc > 0 {
let v = e.arg(idx).clone();
v.call_internal(e, 0)
} 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);
match v {
VVal::Ref(_) | VVal::CRef(_) | VVal::WWRef(_) | VVal::Map(_) | VVal::Usr(_) =>
Ok(v.get_key(&sym).unwrap_or(VVal::Nul)),
_ => Ok(VVal::Nul)
}
} else { Ok(self.clone()) }
})
},
VVal::Map(m) => {
env.with_local_call_info(argc, |e: &mut Env| {
let f = e.arg(0);
let ret = VVal::vec();
for (k, v) in m.borrow_mut().iter() {
e.push(VVal::new_str(k));
e.push(v.clone());
let el = f.call_internal(e, 2);
e.popn(2);
match el {
Ok(v) => { ret.push(v); },
Err(StackAction::Break(v)) => { ret.push(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 ret = VVal::vec();
for i in l.borrow_mut().iter() {
e.push(i.clone());
let el = f.call_internal(e, 1);
e.popn(1);
match el {
Ok(v) => { ret.push(v); },
Err(StackAction::Break(v)) => { ret.push(v); break; },
Err(StackAction::Next) => { },
Err(e) => { return Err(e); },
}
}
Ok(ret)
})
},
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::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.borrow().iter().skip(from)
.take(cnt).copied().collect();
Ok(VVal::new_byt(r))
} else {
let r = vval_bytes.borrow();
if arg_int as usize >= r.len() {
Ok(VVal::Nul)
} else {
Ok(VVal::new_byt(vec![r[arg_int as usize]]))
}
}
},
VVal::Fun(_) => {
let ret = VVal::vec();
for c in vval_bytes.borrow().iter() {
e.push(VVal::new_byt(vec![*c]));
let el = first_arg.call_internal(e, 1);
e.popn(1);
match el {
Ok(v) => { ret.push(v); },
Err(StackAction::Break(v)) => { ret.push(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.borrow().len() - from) as i64))
.i() as usize;
let r : Vec<u8> =
vval_bytes.borrow().iter().skip(from)
.take(cnt).copied().collect();
Ok(VVal::new_byt(r))
},
VVal::Map(_) => Ok(first_arg.get_key(&self.s_raw()).unwrap_or(VVal::Nul)),
_ => Ok(VVal::Nul)
}
} 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;
let r : String = vval_str.borrow().chars().skip(from).take(cnt).collect();
Ok(VVal::new_str_mv(r))
} else {
let r = vval_str.borrow().chars().nth(arg_int as usize);
match r {
None => Ok(VVal::new_str("")),
Some(c) => {
let mut b = [0; 4];
Ok(VVal::new_str(c.encode_utf8(&mut b)))
},
}
}
},
VVal::Fun(_) => {
let ret = VVal::vec();
for c in vval_str.borrow().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.push(v); },
Err(StackAction::Break(v)) => { ret.push(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.borrow().len() - from) as i64)).i() as usize;
let r : String = vval_str.borrow().chars().skip(from).take(cnt).collect();
Ok(VVal::new_str_mv(r))
},
VVal::Str(s2) => {
if argc > 1 {
let mut accum = vval_str.borrow().clone() + &s2.borrow().clone();
for i in 2..argc {
accum += &e.arg(i).s_raw();
}
Ok(VVal::new_str_mv(accum))
} else {
Ok(VVal::new_str_mv(vval_str.borrow().clone() + &s2.borrow().clone()))
}
},
VVal::Map(_) => Ok(first_arg.get_key(&vval_str.borrow()).unwrap_or(VVal::Nul)),
_ => Ok(VVal::Nul)
}
} else { Ok(self.clone()) }
})
},
VVal::Int(i) => {
env.with_local_call_info(argc, |e: &mut Env| {
if argc > 0 {
let v = e.arg(0);
match v {
VVal::Byt(vval_bytes) => {
let bytes = vval_bytes.borrow();
if *i as usize >= bytes.len() {
Ok(VVal::Nul)
} else {
Ok(VVal::new_byt(vec![bytes[*i as usize]]))
}
},
VVal::Str(vval_str) => {
let opt_char = vval_str.borrow().chars().nth(*i as usize);
match opt_char {
None => Ok(VVal::Nul),
Some(char) => {
let mut buf = [0; 4];
Ok(VVal::new_str(char.encode_utf8(&mut buf)))
},
}
},
VVal::Lst(_) =>
Ok(v.at(*i as usize).unwrap_or(VVal::Nul)),
_ => Ok(v.get_key(&format!("{}", *i))
.unwrap_or(VVal::Nul)),
}
} else { Ok(self.clone()) }
})
},
VVal::Usr(ud) => {
env.with_local_call_info(argc, |e: &mut Env| {
let mut args = vec![];
for i in 0..argc { args.push(e.arg(i)) }
ud.call(&args)
})
},
_ => { Ok(self.clone()) },
}
}
pub fn to_ref(&self) -> VVal {
VVal::Ref(Rc::new(RefCell::new(self.clone())))
}
pub fn to_wref(&self) -> VVal {
VVal::CRef(Rc::new(RefCell::new(self.clone())))
}
pub fn set_ref(&self, v: VVal) -> VVal {
match self {
VVal::Ref(r) => r.replace(v),
VVal::CRef(r) => r.replace(v),
VVal::WWRef(l) => {
if let Some(r) = l.upgrade() {
r.replace(v)
} else {
VVal::Nul
}
},
_ => VVal::Nul
}
}
pub fn deref(&self) -> VVal {
match self {
VVal::Ref(l) => (*l).borrow().clone(),
VVal::CRef(l) => (*l).borrow().clone(),
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => v.borrow().clone(),
None => VVal::Nul,
}
},
_ => self.clone()
}
}
pub fn downgrade(self) -> VVal {
match self {
VVal::Ref(f) => VVal::WWRef(Rc::downgrade(&f)),
VVal::CRef(f) => VVal::WWRef(Rc::downgrade(&f)),
_ => self,
}
}
pub fn map() -> VVal {
VVal::Map(Rc::new(RefCell::new(std::collections::HashMap::new())))
}
pub fn sym(s: &str) -> VVal {
VVal::Sym(String::from(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.borrow() as *const String as i64 },
VVal::Byt(s) => { &*s.borrow() as *const Vec<u8> as i64 },
VVal::Lst(v) => { &*v.borrow() as *const Vec<VVal> as i64 },
VVal::Map(v) => { &*v.borrow() as *const std::collections::HashMap<String, VVal> as i64 },
VVal::Fun(f) => { &**f as *const VValFun as i64 },
VVal::DropFun(f) => { &**f as *const DropVVal as i64 },
VVal::Ref(v) => { &*v.borrow() as *const VVal as i64 },
VVal::CRef(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::Nul => { if let VVal::Nul = 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::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.borrow()[..] == s2.borrow()[..] } 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::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::Ref(l) => {
match v {
VVal::Ref(r2) => Rc::ptr_eq(l, r2),
VVal::CRef(r2) => Rc::ptr_eq(l, r2),
VVal::WWRef(r2) =>
match r2.upgrade() {
Some(v2) => Rc::ptr_eq(l, &v2),
None => false,
},
_ => false,
}
},
VVal::CRef(l) => {
match v {
VVal::Ref(r2) => Rc::ptr_eq(l, r2),
VVal::CRef(r2) => Rc::ptr_eq(l, r2),
VVal::WWRef(r2) =>
match r2.upgrade() {
Some(v2) => Rc::ptr_eq(l, &v2),
None => false,
},
_ => false,
}
},
VVal::WWRef(lw) => {
if let Some(l) = lw.upgrade() {
match v {
VVal::Ref(r2) => Rc::ptr_eq(&l, r2),
VVal::CRef(r2) => Rc::ptr_eq(&l, r2),
VVal::WWRef(r2) =>
match r2.upgrade() {
Some(v2) => Rc::ptr_eq(&l, &v2),
None => false,
},
_ => false,
}
} 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_map_as_str(m: &Rc<RefCell<std::collections::HashMap<String,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<&String> = 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.chars().any(char::is_whitespace) {
out.push(format!("\"{}\"", k));
} else {
out.push(k.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_mut().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_mut().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
}
pub fn insert_at(&self, index: usize, val: VVal) {
if let VVal::Lst(b) = &self {
b.borrow_mut().insert(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> {
if let VVal::Lst(b) = &self {
if b.borrow().len() > index {
return Some(b.borrow()[index].clone());
}
}
None
}
pub fn get_key(&self, key: &str) -> Option<VVal> {
match self {
VVal::Ref(_) => self.deref().get_key(key),
VVal::CRef(_) => self.deref().get_key(key),
VVal::WWRef(_) => self.deref().get_key(key),
VVal::Map(m) => {
m.borrow().get(&String::from(key)).cloned()
},
VVal::Lst(l) => {
let idx = usize::from_str_radix(key, 10).unwrap_or(0);
if idx < l.borrow().len() {
Some(l.borrow()[idx].clone())
} else {
Some(VVal::Nul)
}
},
VVal::Usr(u) => u.get_key(key),
_ => None
}
}
pub fn set_map_key(&self, key: String, val: VVal) {
match self {
VVal::Ref(_) => self.deref().set_map_key(key, val),
VVal::CRef(_) => self.deref().set_map_key(key, val),
VVal::WWRef(_) => self.deref().set_map_key(key, val),
VVal::Map(m) => { m.borrow_mut().insert(key, val); },
_ => (),
}
}
pub fn set_key(&self, key: &VVal, val: VVal) {
match self {
VVal::Ref(_) => self.deref().set_key(key, val),
VVal::CRef(_) => self.deref().set_key(key, val),
VVal::WWRef(_) => self.deref().set_key(key, val),
VVal::Map(m) => {
let ks = key.s_raw();
m.borrow_mut().insert(ks, val);
},
VVal::Lst(l) => {
let idx = key.i() as usize;
let mut v = l.borrow_mut();
if v.len() <= idx {
v.resize(idx + 1, VVal::Nul);
}
v[idx] = val;
},
VVal::Usr(u) => { u.set_key(key, val); },
_ => {}
}
}
pub fn pop(&self) -> VVal {
if let VVal::Lst(b) = &self {
b.borrow_mut().pop().unwrap_or(VVal::Nul)
} else {
VVal::Nul
}
}
pub fn push(&self, val: VVal) -> &VVal {
if let VVal::Lst(b) = &self {
b.borrow_mut().push(val);
}
self
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn len(&self) -> usize {
match self {
VVal::Lst(l) => l.borrow().len(),
VVal::Map(l) => l.borrow().len(),
VVal::Byt(l) => l.borrow().len(),
VVal::Str(l) => l.borrow().len(),
VVal::Sym(l) => l.len(),
_ => 0,
}
}
pub fn s_len(&self) -> usize {
match self {
VVal::Str(s) => s.borrow().chars().count(),
VVal::Sym(s) => s.chars().count(),
VVal::Usr(s) => s.s_raw().chars().count(),
VVal::Byt(b) => b.borrow().len(),
_ => self.s().chars().count(),
}
}
pub fn s_raw(&self) -> String {
match self {
VVal::Str(s) => s.borrow().clone(),
VVal::Sym(s) => s.clone(),
VVal::Usr(s) => s.s_raw(),
VVal::Byt(s) => s.borrow().iter().map(|b| *b as char).collect(),
_ => self.s(),
}
}
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_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 {
syn: Syntax::Block,
line: 0, col: 0, file: FileRef::new("?")
}
}
}
pub fn get_syn(&self) -> Syntax {
if let VVal::Syn(s) = self {
s.syn.clone()
} else {
Syntax::Block
}
}
pub fn to_compile_err(&self, msg: String) -> Result<EvalNode, CompileError> {
Err(CompileError {
msg,
pos: self.at(0).unwrap_or(VVal::Nul).get_syn_pos(),
})
}
pub fn is_ref(&self) -> bool {
match self { VVal::Ref(_) => true, VVal::CRef(_) => 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_map(&self) -> bool {
match self { VVal::Map(_) => true, _ => false }
}
pub fn is_none(&self) -> bool {
match self { VVal::Nul => true, _ => false }
}
pub fn is_err(&self) -> bool {
match self { VVal::Err(_) => true, _ => false }
}
pub fn type_name(&self) -> String {
match self {
VVal::Str(_) => String::from("string"),
VVal::Byt(_) => String::from("bytes"),
VVal::Nul => String::from("none"),
VVal::Err(_) => String::from("err"),
VVal::Bol(_) => String::from("bool"),
VVal::Sym(_) => String::from("sym"),
VVal::Syn(_) => String::from("syn"),
VVal::Int(_) => String::from("int"),
VVal::Flt(_) => String::from("float"),
VVal::Lst(_) => String::from("vector"),
VVal::Map(_) => String::from("map"),
VVal::Usr(_) => String::from("userdata"),
VVal::Fun(_) => String::from("function"),
VVal::DropFun(_) => String::from("drop_function"),
VVal::Ref(_) => String::from("ref"),
VVal::CRef(_) => String::from("cref"),
VVal::WWRef(_) => String::from("wref"),
}
}
#[allow(clippy::cast_lossless)]
pub fn f(&self) -> f64 {
match self {
VVal::Str(s) => (*s).borrow().parse::<f64>().unwrap_or(0.0),
VVal::Byt(s) => if (*s).borrow().len() > 0 { (*s).borrow()[0] as f64 } else { 0.0 },
VVal::Nul => 0.0,
VVal::Err(_) => 0.0,
VVal::Bol(b) => if *b { 1.0 } else { 0.0 },
VVal::Sym(s) => s.parse::<f64>().unwrap_or(0.0),
VVal::Syn(s) => (s.syn.clone() as i64) as f64,
VVal::Int(i) => *i as f64,
VVal::Flt(f) => *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::DropFun(f) => f.v.f(),
VVal::Ref(l) => (*l).borrow().f(),
VVal::CRef(l) => (*l).borrow().f(),
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => v.borrow().f(),
None => 0.0,
}
},
}
}
#[allow(clippy::cast_lossless)]
pub fn i(&self) -> i64 {
match self {
VVal::Str(s) => (*s).borrow().parse::<i64>().unwrap_or(0),
VVal::Byt(s) => if (*s).borrow().len() > 0 { (*s).borrow()[0] as i64 } else { 0 as i64 },
VVal::Nul => 0,
VVal::Err(_) => 0,
VVal::Bol(b) => if *b { 1 } else { 0 },
VVal::Sym(s) => s.parse::<i64>().unwrap_or(0),
VVal::Syn(s) => s.syn.clone() as i64,
VVal::Int(i) => *i,
VVal::Flt(f) => (*f as i64),
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::DropFun(f) => f.v.i(),
VVal::Ref(l) => (*l).borrow().i(),
VVal::CRef(l) => (*l).borrow().i(),
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => v.borrow().i(),
None => 0,
}
},
}
}
#[allow(clippy::cast_lossless)]
pub fn b(&self) -> bool {
match self {
VVal::Str(s) => (*s).borrow().parse::<i64>().unwrap_or(0) != 0,
VVal::Byt(s) => (if (*s).borrow().len() > 0 { (*s).borrow()[0] as i64 } else { 0 as i64 }) != 0,
VVal::Nul => false,
VVal::Err(_) => false,
VVal::Bol(b) => *b,
VVal::Sym(s) => s.parse::<i64>().unwrap_or(0) != 0,
VVal::Syn(s) => (s.syn.clone() as i64) != 0,
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::DropFun(f) => f.v.b(),
VVal::Ref(l) => (*l).borrow().i() != 0,
VVal::CRef(l) => (*l).borrow().i() != 0,
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => v.borrow().i() != 0,
None => false,
}
},
}
}
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(s) => format_vval_str(&s.borrow(), false),
VVal::Byt(s) => format!("$b{}", format_vval_byt(&s.borrow())),
VVal::Nul => "$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::Sym(s) => format!(":\"{}\"", s),
VVal::Syn(s) => format!("&{:?}", s.syn),
VVal::Int(i) => i.to_string(),
VVal::Flt(f) => f.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) => f.v.s_cy(c),
VVal::Ref(l) => format!("$&&{}", (*l).borrow().s_cy(c)),
VVal::CRef(l) => format!("$&{}", (*l).borrow().s_cy(c)),
VVal::WWRef(l) => {
match l.upgrade() {
Some(v) => format!("$(&){}", v.borrow().s_cy(c)),
None => "$n".to_string(),
}
},
};
format!("{}{}", br, 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(_) => serializer.serialize_str(&self.s_raw()),
VVal::Sym(_) => serializer.serialize_str(&self.s_raw()),
VVal::Byt(b) => serializer.serialize_bytes(&b.borrow()[..]),
VVal::Nul => 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::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, v)?;
}
map.end()
},
VVal::Usr(_) => serializer.serialize_str(&self.s()),
VVal::Fun(_) => serializer.serialize_str(&self.s()),
VVal::DropFun(_) => serializer.serialize_str(&self.s()),
VVal::Ref(_) => self.deref().serialize(serializer),
VVal::CRef(_) => 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::Nul) }
fn visit_unit<E>(self) -> Result<Self::Value, E>
where E: serde::de::Error { Ok(VVal::Nul) }
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(&VVal::new_sym(&k.s_raw()), ve);
}
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)
}
}