#![allow(dead_code)]
use std::fmt::{self, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::{cell::RefCell, cmp::Ordering, rc::Rc};
use super::env::Environment;
use super::num::{to_u32, Num};
use super::tokens::Node;
use crate::{FLOAT_PRECISION, OUTPUT_PRECISION};
pub type Env = Rc<RefCell<Environment>>;
#[derive(Clone, Debug)]
pub enum Val {
String(String),
Number(Num),
Boolean(bool),
Array(Box<Sequence>),
Empty,
}
impl Hash for Val {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Val::String(s) => s.hash(state),
Val::Number(n) => n.clone().floor().to_u32_saturating().unwrap().hash(state),
Val::Boolean(b) => b.hash(state),
Val::Array(s) => s.as_ref().clone().collect::<Vec<Dynamic>>().hash(state),
Val::Empty => "".hash(state),
}
}
}
#[derive(Clone, Debug, Hash)]
pub struct Dynamic {
val: Val,
cur: u8,
}
#[allow(clippy::clippy::wrong_self_convention)]
impl Dynamic {
pub fn empty() -> Self {
Self {
val: Val::Empty,
cur: 0,
}
}
pub fn new(val: Val, cur: u8) -> Self {
Self { val, cur }
}
#[inline]
pub fn as_string(&mut self) {
*self = self.into_string();
}
#[inline]
pub fn as_num(&mut self) {
*self = self.into_num();
}
#[inline]
pub fn as_bool(&mut self) {
*self = self.into_bool();
}
pub fn into_string(&self) -> Self {
match &self.val {
Val::String(_) => self.clone(),
Val::Number(_) => Self {
val: Val::String(format!("{}", self)),
cur: 1,
},
Val::Boolean(b) => Self {
val: Val::String(b.to_string()),
cur: 1,
},
Val::Array(n) => Self {
val: Val::String(
n.clone()
.next()
.unwrap_or_else(|| Dynamic::from(""))
.literal_string(),
),
cur: 1,
},
Val::Empty => Self {
val: Val::String(String::new()),
cur: 1,
},
}
}
pub fn into_num(&self) -> Self {
match &self.val {
Val::String(s) => Self {
val: Val::Number(Num::with_val(
*FLOAT_PRECISION,
Num::parse(s).unwrap_or_else(|_| Num::parse("0").unwrap()),
)),
cur: 2,
},
Val::Number(_) => self.clone(),
Val::Boolean(b) => Self {
val: Val::Number(Num::with_val(*FLOAT_PRECISION, if *b { 1 } else { 0 })),
cur: 2,
},
Val::Array(n) => Self {
val: Val::Number(Num::with_val(
*FLOAT_PRECISION,
Num::parse(
n.clone()
.next()
.unwrap_or_else(|| Dynamic::from(""))
.literal_string(),
)
.unwrap_or_else(|_| Num::parse("0").unwrap()),
)),
cur: 2,
},
Val::Empty => Self {
val: Val::Number(Num::with_val(*FLOAT_PRECISION, 0)),
cur: 2,
},
}
}
pub fn into_bool(&self) -> Self {
match &self.val {
Val::String(s) => Self {
val: Val::Boolean(!s.is_empty()),
cur: 3,
},
Val::Number(n) => Self {
val: Val::Boolean(*n != 0),
cur: 3,
},
Val::Boolean(_) => self.clone(),
Val::Array(n) => Self {
val: Val::Boolean(
n.clone()
.next()
.unwrap_or_else(|| Dynamic::from(false))
.literal_bool(),
),
cur: 3,
},
Val::Empty => Self {
val: Val::Boolean(false),
cur: 3,
},
}
}
pub fn into_array(&self) -> Self {
match &self.val {
Val::String(s) => {
if s.contains(' ') {
let iter = s.split(' ').map(Dynamic::from);
Self {
val: Val::Array(Box::new(Sequence::from_iter(
iter.clone(),
Node::String(String::new()),
Some(iter.count()),
))),
cur: 4,
}
} else {
let iter = s.chars().map(|n| Dynamic::from(n.to_string()));
Self {
val: Val::Array(Box::new(Sequence::from_iter(
iter.clone(),
Node::String(String::new()),
Some(iter.count()),
))),
cur: 4,
}
}
}
Val::Number(_) => Dynamic::from(format!("{}", self)).into_array(),
Val::Boolean(_) => Dynamic::from(format!("{}", self)).into_array(),
Val::Array(_) => self.clone(),
Val::Empty => Self {
val: Val::Array(Box::new(Sequence::from_vec::<String>(
&[],
Node::String(String::new()),
Some(0),
))),
cur: 4,
},
}
}
#[inline]
pub fn literal_num(self) -> Num {
match self.val {
Val::Number(n) => n,
_ => self.into_num().literal_num(),
}
}
#[inline]
pub fn literal_string(self) -> String {
match self.val {
Val::String(s) => s,
_ => self.into_string().literal_string(),
}
}
#[inline]
pub fn literal_bool(self) -> bool {
match self.val {
Val::Boolean(b) => b,
_ => self.into_bool().literal_bool(),
}
}
#[inline]
pub fn literal_array(self) -> Sequence {
match &self.val {
Val::Array(seq) => seq.as_ref().clone(),
_ => self.into_array().literal_array(),
}
}
#[inline]
pub fn is_string(&self) -> bool {
self.cur == 1
}
#[inline]
pub fn is_num(&self) -> bool {
self.cur == 2
}
#[inline]
pub fn is_bool(&self) -> bool {
self.cur == 3
}
#[inline]
pub fn is_array(&self) -> bool {
self.cur == 4
}
pub fn mutate_string<T: FnOnce(String) -> String>(&self, f: T) -> Self {
match &self.val {
Val::String(s) => Self::from(f(s.clone())),
_ => self.into_string().mutate_string(f),
}
}
pub fn mutate_num<T: FnOnce(Num) -> Num>(&self, f: T) -> Self {
match &self.val {
Val::Number(n) => Self::from(f(n.clone())),
_ => self.into_num().mutate_num(f),
}
}
pub fn mutate_bool<T: FnOnce(bool) -> bool>(&self, f: T) -> Self {
match &self.val {
Val::Boolean(b) => Self::from(f(*b)),
_ => self.into_bool().mutate_bool(f),
}
}
pub fn mutate_array<T: FnOnce(&mut Sequence) -> &mut Sequence>(&mut self, f: T) -> Self {
match &mut self.val {
Val::Array(seq) => Self {
val: Val::Array(Box::new(f(seq.as_mut()).clone())),
cur: 4,
},
_ => self.into_array().mutate_array(f),
}
}
pub fn into_node(self) -> Node {
match self.val {
Val::String(s) => Node::String(s),
Val::Number(n) => Node::Number(n),
Val::Boolean(b) => Node::Number(Num::with_val(*FLOAT_PRECISION, if b { 1 } else { 0 })),
Val::Array(s) => {
if !s.is_finite() {
panic!("Cannot convert infinite sequence into Node");
}
let s = s.as_ref().clone();
Node::Sequence(
s.cstr.iter().cloned().map(Dynamic::into_node).collect(),
Box::new(s.block),
s.length
.map(|n| Box::new(Node::Number(Num::with_val(*FLOAT_PRECISION, n)))),
)
}
Val::Empty => unreachable!(),
}
}
}
impl Display for Dynamic {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match &self.val {
Val::String(s) => write!(f, "{}", s),
Val::Number(n) => {
let s = n.to_string_radix_round(
10,
Some(*OUTPUT_PRECISION),
rug::float::Round::Nearest,
);
write!(
f,
"{}",
if s.contains('.') && !s.contains('e') {
s.trim_end_matches('0')
.trim_end_matches('.')
.replace('-', "_")
} else {
s.replace('-', "_")
}
)
}
Val::Boolean(b) => write!(f, "{}", if *b { 1 } else { 0 }),
Val::Array(seq) => {
let seq = seq.as_ref().clone();
let is_infinite = !seq.is_finite();
for entry in seq {
let mut as_string = format!("{}", entry);
if entry.is_array() {
as_string = as_string.replace('\n', " ");
}
if is_infinite {
println!("{}", as_string);
} else {
writeln!(f, "{}", as_string)?;
}
}
Ok(())
}
Val::Empty => write!(f, ""),
}
}
}
impl PartialEq for Dynamic {
#[inline]
fn eq(&self, other: &Self) -> bool {
match &self.val {
Val::String(s) => match &other.val {
Val::String(o) => s == o,
Val::Number(n) => match Num::parse(s) {
Ok(s) => Num::with_val(*FLOAT_PRECISION, s) == n.clone(),
Err(_) => false,
},
Val::Boolean(b) => {
if *b {
s == "1"
} else {
s == "0"
}
}
_ => false,
},
Val::Number(n) => match &other.val {
Val::String(s) => match Num::parse(s) {
Ok(s) => Num::with_val(*FLOAT_PRECISION, s) == n.clone(),
Err(_) => false,
},
Val::Number(o) => n == o,
Val::Boolean(b) => {
if *b {
n.clone() == 1
} else {
n.is_zero()
}
}
_ => false,
},
Val::Boolean(b) => match &other.val {
Val::Number(n) => {
if *b {
n.clone() == 1
} else {
n.is_zero()
}
}
Val::Boolean(n) => b == n,
_ => false,
},
Val::Array(_) => todo!(),
Val::Empty => matches!(other.val, Val::Empty),
}
}
}
impl Eq for Dynamic {}
impl PartialOrd for Dynamic {
#[inline]
fn partial_cmp(&self, other: &Dynamic) -> Option<Ordering> {
match &self.val {
Val::String(s) => match &other.val {
Val::String(o) => s.partial_cmp(o),
Val::Number(n) => match Num::parse(s) {
Ok(s) => Num::with_val(*FLOAT_PRECISION, s).partial_cmp(n),
Err(_) => None,
},
Val::Boolean(b) => {
if *b {
s.partial_cmp(&"1".to_string())
} else {
s.partial_cmp(&"0".to_string())
}
}
_ => s.partial_cmp(&other.clone().literal_string()),
},
Val::Number(n) => match &other.val {
Val::String(s) => match Num::parse(s) {
Ok(s) => n.partial_cmp(&Num::with_val(*FLOAT_PRECISION, s)),
Err(_) => None,
},
Val::Number(o) => n.partial_cmp(o),
Val::Boolean(b) => {
if *b {
n.partial_cmp(&1)
} else {
n.cmp0()
}
}
_ => n.partial_cmp(&other.clone().literal_num()),
},
Val::Boolean(b) => match &other.val {
Val::Number(n) => {
if *b {
Num::with_val(*FLOAT_PRECISION, 1).partial_cmp(&1)
} else {
Num::new(*FLOAT_PRECISION).partial_cmp(n)
}
}
Val::Boolean(n) => b.partial_cmp(n),
_ => b.partial_cmp(&other.clone().literal_bool()),
},
Val::Array(s) => match &other.val {
Val::Array(o) => {
let s = s.as_ref().clone().count();
let o = o.as_ref().clone().count();
s.partial_cmp(&o)
}
_ => s
.as_ref()
.clone()
.collect::<Vec<_>>()
.partial_cmp(&other.clone().literal_array().collect::<Vec<_>>()),
},
Val::Empty => None,
}
}
}
impl<'a> From<&'a str> for Dynamic {
fn from(v: &'a str) -> Self {
Self {
val: Val::String(v.to_owned()),
cur: 1,
}
}
}
impl From<String> for Dynamic {
fn from(v: String) -> Self {
Self {
val: Val::String(v),
cur: 1,
}
}
}
impl From<Num> for Dynamic {
fn from(v: Num) -> Self {
Self {
val: Val::Number(v),
cur: 2,
}
}
}
impl From<bool> for Dynamic {
fn from(v: bool) -> Self {
Self {
val: Val::Boolean(v),
cur: 3,
}
}
}
impl<'a, T> From<&'a [T]> for Dynamic
where
Dynamic: From<T>,
T: Clone,
{
fn from(v: &'a [T]) -> Self {
Self {
val: Val::Array(Box::new(Sequence::from_vec(
v,
Node::Block(vec![], None),
Some(v.len()),
))),
cur: 4,
}
}
}
impl<T> From<Vec<T>> for Dynamic
where
Dynamic: From<T>,
T: Clone,
{
fn from(v: Vec<T>) -> Self {
Self {
val: Val::Array(Box::new(Sequence::from_vec(
&v,
Node::Block(vec![], None),
Some(v.len()),
))),
cur: 4,
}
}
}
impl<T, const N: usize> From<[T; N]> for Dynamic
where
Dynamic: From<T>,
T: Clone,
{
fn from(v: [T; N]) -> Self {
Self {
val: Val::Array(Box::new(Sequence::from_vec(
&v,
Node::Block(vec![], None),
Some(N),
))),
cur: 4,
}
}
}
impl From<Sequence> for Dynamic {
fn from(v: Sequence) -> Self {
Self {
val: Val::Array(Box::new(v)),
cur: 4,
}
}
}
impl From<Node> for Dynamic {
fn from(v: Node) -> Self {
crate::parser::parse_node(Rc::new(RefCell::new(Environment::init())), &v)
}
}
#[allow(clippy::from_over_into)]
impl Into<Node> for Dynamic {
fn into(self) -> Node {
match self.val {
Val::String(st) => Node::String(st),
Val::Number(nm) => Node::Number(nm),
Val::Boolean(bl) => {
Node::Number(Num::with_val(*FLOAT_PRECISION, if bl { 1 } else { 0 }))
}
_ => panic!("Cannot convert emtpy value into Node"),
}
}
}
#[derive(Clone, Debug)]
pub struct Sequence {
pub cstr: Vec<Dynamic>,
pub length: Option<usize>,
pub block: Node,
unparsed_length: Option<Node>,
t_i: Option<isize>,
env: Option<Env>,
index: usize,
}
impl Sequence {
pub fn from_iter<T, U>(iter: T, block: Node, length: Option<usize>) -> Self
where
T: Iterator<Item = U>,
Dynamic: From<U>,
{
let v = iter.map(Dynamic::from).collect();
Self {
cstr: v,
unparsed_length: None,
length,
block,
t_i: None,
env: None,
index: 0,
}
}
pub fn from_vec<T>(v: &[T], block: Node, length: Option<usize>) -> Self
where
Dynamic: From<T>,
T: Clone,
{
let v = v.iter().map(|n| Dynamic::from(n.clone())).collect();
Self {
cstr: v,
unparsed_length: None,
length,
block,
t_i: None,
env: None,
index: 0,
}
}
pub fn from_vec_dyn(v: &[Dynamic], block: Node, length: Option<usize>) -> Self {
Self {
cstr: v.to_owned(),
unparsed_length: None,
length,
block,
t_i: None,
env: None,
index: 0,
}
}
#[inline]
pub fn is_finite(&self) -> bool {
self.length.is_some() || self.unparsed_length.is_some()
}
#[inline]
pub fn len(&self) -> Option<usize> {
self.length
}
#[inline]
pub fn set_env(&mut self, env: Env) {
self.env = Some(Rc::new(env.as_ref().clone()));
}
#[inline]
pub fn set_env_self(self, env: Env) -> Self {
Self {
cstr: self.cstr,
unparsed_length: self.unparsed_length,
length: self.length,
block: self.block,
t_i: self.t_i,
env: Some(env),
index: self.index,
}
}
fn traverse_replace(&mut self, n: Node) -> Node {
let mut vals = self.cstr.iter().cloned().map(|n| n.into_node()).collect();
if let Node::Block(mut body, n) = n {
for i in 0..body.len() {
body[i] = super::traverse_replace(&mut vals, body[i].clone());
}
Node::Block(body, n)
} else {
unreachable!()
}
}
#[allow(clippy::unnecessary_wraps)]
#[inline]
fn _next(&mut self) -> Option<Dynamic> {
if self.index < self.cstr.len() {
self.index += 1;
Some(self.cstr[self.index - 1].clone())
} else {
self.index += 1;
let block = self.traverse_replace(self.block.clone());
self.env
.as_ref()
.unwrap()
.borrow_mut()
.define_var("p", Dynamic::from(self.cstr.as_slice()));
let res = crate::parser::parse_node(Rc::clone(self.env.as_ref().unwrap()), &block);
self.cstr.push(res.clone());
Some(res)
}
}
}
impl Iterator for Sequence {
type Item = Dynamic;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.length.is_none() && self.unparsed_length.is_some() {
self.length = Some(to_u32(
self.env.as_ref().unwrap(),
self.unparsed_length.as_ref().unwrap(),
) as usize);
}
if self.length.is_none() {
self._next()
} else if self.index == self.length.unwrap() {
None
} else {
self._next()
}
}
}
impl DoubleEndedIterator for Sequence {
fn next_back(&mut self) -> Option<Dynamic> {
if self.len().is_none() {
panic!("Can only implement DoubleEndedIterator for a finite Sequence");
}
while let Some(_) = self.next() {
self.t_i = Some(self.index as isize - 1);
}
if self.t_i.unwrap() < 0 {
None
} else {
self.t_i = Some(self.t_i.unwrap() - 1);
Some(self.cstr[(self.t_i.unwrap() + 1) as usize].clone())
}
}
}