use std::fmt::{Debug, Display};
use std::hash::Hash;
use crate::data::{SimpleData, SimpleDataList};
impl<T> SimpleData<T>
where
T: Clone + Copy + PartialEq + Eq + PartialOrd + Debug + Hash,
{
pub fn display_simple(&self) -> String
where
T: Display,
{
match self {
SimpleData::Unit => "()".into(),
SimpleData::True => "True".into(),
SimpleData::False => "False".into(),
SimpleData::Type(t) => format!("Type({:?})", t),
SimpleData::Number(n) => format!("{}", n),
SimpleData::Char(c) => format!("\"{}\"", c),
SimpleData::Byte(b) => b.to_string(),
SimpleData::Symbol(s) => format!("Symbol({})", s),
SimpleData::Expression(e) => format!("Expression({})", e),
SimpleData::External(e) => format!("External({})", e),
SimpleData::CharList(s) => format!("\"{}\"", s),
SimpleData::ByteList(l) => format!("'{}'", l.iter().map(|b| b.to_string()).collect::<Vec<String>>().join(" ")),
SimpleData::Pair(l, r) => format!("Pair({}, {})", l, r),
SimpleData::Range(s, e) => format!("Range({}, {})", s, e),
SimpleData::Slice(l, r) => format!("Slice({}, {})", l, r),
SimpleData::List(i, h) => format!(
"List([{}], [{}])",
i.iter().map(|i| i.to_string()).collect::<Vec<String>>().join(", "),
h.iter().map(|i| i.to_string()).collect::<Vec<String>>().join(", ")
),
SimpleData::Concatenation(l, r) => format!("Concatenation({}, {})", l, r),
SimpleData::StackFrame(s) => format!("StackFrame{{return: {}}}", s.return_addr()),
SimpleData::Custom(c) => format!("{}", c),
}
}
}
impl<T> SimpleDataList<T>
where
T: Clone + Copy + PartialEq + Eq + PartialOrd + Debug + Hash,
{
pub fn display_for_item(&self, index: usize) -> String
where
T: Display,
{
self.display_for_item_internal(index, 0)
}
fn display_for_item_internal(&self, index: usize, level: usize) -> String
where
T: Display,
{
match self.get(index) {
None => String::from("<NoData>"),
Some(item) => match item {
SimpleData::Symbol(s) => match self.symbol_to_name.get(s) {
None => item.display_simple(),
Some(s) => format!(";{}", s),
},
SimpleData::Expression(i) => match self.expression_to_symbol.get(i).and_then(|s| self.symbol_to_name.get(s)) {
None => item.display_simple(),
Some(s) => format!("Expression({})", s),
},
SimpleData::External(i) => match self.external_to_symbol.get(i).and_then(|s| self.symbol_to_name.get(s)) {
None => item.display_simple(),
Some(s) => format!("External({})", s),
},
SimpleData::ByteList(bytes) => match level > 0 {
true => format!("({})", bytes.iter().map(|b| b.to_string()).collect::<Vec<String>>().join(" ")),
false => format!("{}", bytes.iter().map(|b| b.to_string()).collect::<Vec<String>>().join(" ")),
},
SimpleData::Pair(left, right) => {
format!(
"{} = {}",
self.display_for_item_internal(*left, level + 1),
self.display_for_item_internal(*right, level + 1)
)
}
SimpleData::Range(start, end) => format!(
"{}..{}",
self.display_for_item_internal(*start, level + 1),
self.display_for_item_internal(*end, level + 1)
),
SimpleData::Concatenation(left, right) => {
let mut stack = vec![right, left];
let mut parts = vec![];
while let Some(item_index) = stack.pop() {
match self.get(*item_index) {
None => parts.push("<NoData>".to_string()),
Some(item) => match item {
SimpleData::Concatenation(left, right) => {
stack.push(right);
stack.push(left);
}
_ => parts.push(self.display_for_item_internal(*item_index, level)),
},
}
}
let base = parts.join(", ");
match level > 0 {
true => format!("({})", base),
false => base,
}
}
SimpleData::List(items, _) => {
let base = items
.iter()
.map(|item| self.display_for_item_internal(*item, level + 1))
.collect::<Vec<String>>()
.join(", ");
match level > 0 {
true => format!("({})", base),
false => base,
}
}
SimpleData::Slice(list, range) => {
let (start, end) = match self.get(*range) {
None => return format!("Slice({}, <NoData>)", list),
Some(item) => match item {
SimpleData::Range(start, end) => match (self.get(*start), self.get(*end)) {
(Some(SimpleData::Number(s)), Some(SimpleData::Number(e))) => {
(s.to_integer().as_integer().unwrap(), e.to_integer().as_integer().unwrap())
}
(Some(SimpleData::Number(_s)), Some(_e)) => {
return format!("Slice({}, {}..{}", list, start, self.display_for_item_internal(*end, level + 1))
}
(Some(_s), Some(SimpleData::Number(_e))) => {
return format!("Slice({}, {}..{}", list, self.display_for_item_internal(*start, level + 1), end)
}
(Some(_s), Some(_e)) => {
return format!(
"Slice({}, ({})..({})",
list,
self.display_for_item_internal(*start, level + 1),
self.display_for_item_internal(*end, level + 1)
)
}
(Some(_s), None) => {
return format!("Slice({}, ({})..<NoData>", list, self.display_for_item_internal(*start, level + 1))
}
(None, Some(_e)) => {
return format!("Slice({}, <NoData>..({})", list, self.display_for_item_internal(*end, level + 1))
}
(None, None) => return format!("Slice({}, <NoData>..<NoData>", list),
},
_ => return format!("Slice({}, <NotARange>)", list),
},
};
if start < 0 || end < 0 || start > end {
return String::from(format!("Slice({}, {}..{})", list, start, end));
}
let (start, end) = (start as usize, end as usize);
let count = end - start + 1;
match self.get(*list) {
None => format!("Slice(<NoData>, {}..{})", start, end),
Some(item) => match item {
SimpleData::List(items, _) => {
let base = items
.iter()
.skip(start)
.take(count)
.map(|item| self.display_for_item_internal(*item, level + 1))
.collect::<Vec<String>>()
.join(", ");
match level > 0 {
true => format!("({})", base),
false => base,
}
}
SimpleData::Concatenation(left, right) => {
let mut stack = vec![right, left];
let mut parts = vec![];
while let Some(item_index) = stack.pop() {
match self.get(*item_index) {
None => parts.push("<NoData>".to_string()),
Some(item) => match item {
SimpleData::Concatenation(left, right) => {
stack.push(right);
stack.push(left);
}
SimpleData::List(items, _) => {
for i in items {
parts.push(self.display_for_item_internal(*i, level + 1));
}
}
_ => parts.push(self.display_for_item_internal(*item_index, level)),
},
}
}
let base = parts.into_iter().skip(start).take(count).collect::<Vec<String>>().join(", ");
match level > 0 {
true => format!("({})", base),
false => base,
}
}
_ => format!("Slice({}, {}..{})", self.display_for_item_internal(*list, level + 1), start, end),
},
}
}
_ => item.display_simple(),
},
}
}
}
#[cfg(test)]
mod shared {
use std::fmt::{Display, Formatter};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Hash)]
pub struct StructWith {}
impl Display for StructWith {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("StructWith")
}
}
}
#[cfg(test)]
mod simple {
use garnish_lang_traits::GarnishDataType;
use crate::data::display::shared::StructWith;
use crate::data::{SimpleData, SimpleNumber};
use crate::data::stack_frame::SimpleStackFrame;
use crate::NoCustom;
#[test]
fn simple_unit() {
let data: SimpleData<NoCustom> = SimpleData::Unit;
assert_eq!(data.display_simple(), "()".to_string());
}
#[test]
fn simple_true() {
let data: SimpleData<NoCustom> = SimpleData::True;
assert_eq!(data.display_simple(), "True".to_string());
}
#[test]
fn simple_false() {
let data: SimpleData<NoCustom> = SimpleData::False;
assert_eq!(data.display_simple(), "False".to_string());
}
#[test]
fn simple_type() {
let data: SimpleData<NoCustom> = SimpleData::Type(GarnishDataType::Byte);
assert_eq!(data.display_simple(), "Type(Byte)".to_string());
}
#[test]
fn simple_number() {
let data: SimpleData<NoCustom> = SimpleData::Number(SimpleNumber::Integer(100));
assert_eq!(data.display_simple(), "100".to_string());
}
#[test]
fn simple_char() {
let data: SimpleData<NoCustom> = SimpleData::Char('c');
assert_eq!(data.display_simple(), "\"c\"".to_string());
}
#[test]
fn simple_symbol() {
let data: SimpleData<NoCustom> = SimpleData::Symbol(100);
assert_eq!(data.display_simple(), "Symbol(100)".to_string());
}
#[test]
fn simple_expression() {
let data: SimpleData<NoCustom> = SimpleData::Expression(100);
assert_eq!(data.display_simple(), "Expression(100)".to_string());
}
#[test]
fn simple_external() {
let data: SimpleData<NoCustom> = SimpleData::External(100);
assert_eq!(data.display_simple(), "External(100)".to_string());
}
#[test]
fn simple_character_list() {
let data: SimpleData<NoCustom> = SimpleData::CharList("test".to_string());
assert_eq!(data.display_simple(), "\"test\"".to_string());
}
#[test]
fn simple_byte_list() {
let data: SimpleData<NoCustom> = SimpleData::ByteList(vec![10, 20]);
assert_eq!(data.display_simple(), "'10 20'".to_string());
}
#[test]
fn simple_pair() {
let data: SimpleData<NoCustom> = SimpleData::Pair(10, 20);
assert_eq!(data.display_simple(), "Pair(10, 20)".to_string());
}
#[test]
fn simple_range() {
let data: SimpleData<NoCustom> = SimpleData::Range(10, 20);
assert_eq!(data.display_simple(), "Range(10, 20)".to_string());
}
#[test]
fn simple_slice() {
let data: SimpleData<NoCustom> = SimpleData::Slice(10, 20);
assert_eq!(data.display_simple(), "Slice(10, 20)".to_string());
}
#[test]
fn simple_concatenation() {
let data: SimpleData<NoCustom> = SimpleData::Concatenation(10, 20);
assert_eq!(data.display_simple(), "Concatenation(10, 20)".to_string());
}
#[test]
fn simple_list() {
let data: SimpleData<NoCustom> = SimpleData::List(vec![10, 20], vec![20, 10]);
assert_eq!(data.display_simple(), "List([10, 20], [20, 10])".to_string());
}
#[test]
fn simple_stack_frame() {
let data: SimpleData<NoCustom> = SimpleData::StackFrame(SimpleStackFrame::new(5));
assert_eq!(data.display_simple(), "StackFrame{return: 5}".to_string());
}
#[test]
fn simple_custom() {
let data: SimpleData<StructWith> = SimpleData::Custom(StructWith {});
assert_eq!(data.display_simple(), "StructWith".to_string());
}
}
#[cfg(test)]
mod simple_list {
use garnish_lang_traits::GarnishDataType;
use crate::data::display::shared::StructWith;
use crate::data::{SimpleData, SimpleDataList, SimpleNumber};
#[test]
fn non_existent_item_is_none() {
let list: SimpleDataList<StructWith> = SimpleDataList::new();
assert_eq!(list.display_for_item(10), "<NoData>".to_string())
}
#[test]
fn list_of_items() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Unit);
list.push(SimpleData::True);
list.push(SimpleData::False);
list.push(SimpleData::Type(GarnishDataType::Byte));
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::Char('c'));
list.push(SimpleData::Byte(10));
list.push(SimpleData::Symbol(100));
list.push(SimpleData::Expression(100));
list.push(SimpleData::External(100));
list.push(SimpleData::CharList("test".to_string()));
list.push(SimpleData::ByteList(vec![10, 20]));
list.push(SimpleData::Custom(StructWith {}));
list.push(SimpleData::List(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15], vec![]));
assert_eq!(
list.display_for_item(13),
"(), True, False, Type(Byte), 100, \"c\", 10, Symbol(100), Expression(100), External(100), \"test\", (10 20), StructWith, <NoData>"
);
}
#[test]
fn symbol_name() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.insert_symbol(100, "my_symbol");
list.push(SimpleData::Symbol(100));
assert_eq!(list.display_for_item(0), ";my_symbol");
}
#[test]
fn symbol_no_name() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Symbol(100));
assert_eq!(list.display_for_item(0), "Symbol(100)");
}
#[test]
fn expression_name() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.insert_symbol(100, "my_expression");
list.insert_expression(1, 100);
list.push(SimpleData::Expression(1));
assert_eq!(list.display_for_item(0), "Expression(my_expression)");
}
#[test]
fn expression_no_name() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.insert_symbol(100, "my_expression");
list.push(SimpleData::Expression(1));
assert_eq!(list.display_for_item(0), "Expression(1)");
}
#[test]
fn external_name() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.insert_symbol(100, "my_external");
list.insert_external(1, 100);
list.push(SimpleData::External(1));
assert_eq!(list.display_for_item(0), "External(my_external)");
}
#[test]
fn external_no_name() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.insert_symbol(100, "my_external");
list.push(SimpleData::External(1));
assert_eq!(list.display_for_item(0), "External(1)");
}
#[test]
fn pair() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::CharList("test".to_string()));
list.push(SimpleData::Pair(0, 1));
assert_eq!(list.display_for_item(2), "100 = \"test\"");
}
#[test]
fn pair_nested() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::CharList("test".to_string()));
list.push(SimpleData::Pair(0, 1));
list.push(SimpleData::Number(SimpleNumber::Integer(200)));
list.push(SimpleData::Pair(3, 2));
assert_eq!(list.display_for_item(4), "200 = 100 = \"test\"");
}
#[test]
fn range() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::Number(SimpleNumber::Integer(200)));
list.push(SimpleData::Range(0, 1));
assert_eq!(list.display_for_item(2), "100..200");
}
#[test]
fn concatenation() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::Number(SimpleNumber::Integer(200)));
list.push(SimpleData::Number(SimpleNumber::Integer(300)));
list.push(SimpleData::Number(SimpleNumber::Integer(400)));
list.push(SimpleData::Concatenation(0, 1));
list.push(SimpleData::Concatenation(4, 2));
list.push(SimpleData::Concatenation(3, 5));
assert_eq!(list.display_for_item(6), "400, 100, 200, 300");
}
#[test]
fn concatenation_of_list_with_concatenation_and_list() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100))); list.push(SimpleData::Number(SimpleNumber::Integer(200)));
list.push(SimpleData::Concatenation(0, 1)); list.push(SimpleData::Number(SimpleNumber::Integer(300)));
list.push(SimpleData::Number(SimpleNumber::Integer(400)));
list.push(SimpleData::Number(SimpleNumber::Integer(500))); list.push(SimpleData::Number(SimpleNumber::Integer(600))); list.push(SimpleData::Number(SimpleNumber::Integer(700)));
list.push(SimpleData::List(vec![5, 6, 7], vec![]));
list.push(SimpleData::List(vec![2, 3], vec![])); list.push(SimpleData::List(vec![4, 8], vec![]));
list.push(SimpleData::Concatenation(9, 10));
assert_eq!(list.display_for_item(11), "(100, 200), 300, 400, (500, 600, 700)");
}
#[test]
fn slice_of_list() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::Number(SimpleNumber::Integer(200)));
list.push(SimpleData::Number(SimpleNumber::Integer(300)));
list.push(SimpleData::Number(SimpleNumber::Integer(400)));
list.push(SimpleData::Number(SimpleNumber::Integer(500)));
list.push(SimpleData::Number(SimpleNumber::Integer(600)));
list.push(SimpleData::Number(SimpleNumber::Integer(700)));
list.push(SimpleData::Number(SimpleNumber::Integer(2)));
list.push(SimpleData::Number(SimpleNumber::Integer(5)));
list.push(SimpleData::List(vec![0, 1, 2, 3, 4, 5, 6], vec![]));
list.push(SimpleData::Range(7, 8));
list.push(SimpleData::Slice(9, 10));
assert_eq!(list.display_for_item(11), "300, 400, 500, 600");
}
#[test]
fn slice_of_concatenation() {
let mut list: SimpleDataList<StructWith> = SimpleDataList::new();
list.push(SimpleData::Number(SimpleNumber::Integer(100)));
list.push(SimpleData::Number(SimpleNumber::Integer(200)));
list.push(SimpleData::Number(SimpleNumber::Integer(300)));
list.push(SimpleData::Number(SimpleNumber::Integer(400)));
list.push(SimpleData::Number(SimpleNumber::Integer(500)));
list.push(SimpleData::Number(SimpleNumber::Integer(600)));
list.push(SimpleData::Number(SimpleNumber::Integer(700)));
list.push(SimpleData::Number(SimpleNumber::Integer(2)));
list.push(SimpleData::Number(SimpleNumber::Integer(5)));
list.push(SimpleData::List(vec![0, 1, 2, 3], vec![]));
list.push(SimpleData::List(vec![4, 5, 6], vec![]));
list.push(SimpleData::Concatenation(9, 10));
list.push(SimpleData::Range(7, 8));
list.push(SimpleData::Slice(11, 12));
assert_eq!(list.display_for_item(13), "300, 400, 500, 600");
}
}