From ed4820a1372c22888668c1f131809e510bad43b8 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 19 Jun 2024 04:56:56 -0400 Subject: [PATCH] Implement serde traits for Value --- dust-lang/src/abstract_tree/list_index.rs | 2 +- dust-lang/src/abstract_tree/value_node.rs | 9 ++-- dust-lang/src/identifier.rs | 38 +++++++++++--- dust-lang/src/lib.rs | 18 +++---- dust-lang/src/value.rs | 62 +++++++++++------------ dust-lang/tests/values.rs | 8 +-- examples/assets/data.json | 6 +++ 7 files changed, 84 insertions(+), 59 deletions(-) create mode 100644 examples/assets/data.json diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index b242a91..6963cb2 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -82,7 +82,7 @@ impl AbstractNode for ListIndex { let found_item = list.get(index as usize); if let Some(item) = found_item { - Ok(Evaluation::Return(item.node.clone())) + Ok(Evaluation::Return(item.clone())) } else { Ok(Evaluation::None) } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 0b11883..0899bc0 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -149,12 +149,9 @@ impl AbstractNode for ValueNode { for expression in expression_list { let expression_position = expression.position(); - let action = expression.evaluate(context, _manage_memory)?; - let value = if let Evaluation::Return(value) = action { - WithPosition { - node: value, - position: expression_position, - } + let evaluation = expression.evaluate(context, _manage_memory)?; + let value = if let Evaluation::Return(value) = evaluation { + value } else { return Err(RuntimeError::ValidationFailure( ValidationError::InterpreterExpectedReturn(expression_position), diff --git a/dust-lang/src/identifier.rs b/dust-lang/src/identifier.rs index d0eb837..4caf0e5 100644 --- a/dust-lang/src/identifier.rs +++ b/dust-lang/src/identifier.rs @@ -38,18 +38,44 @@ impl<'de> Deserialize<'de> for Identifier { where D: serde::Deserializer<'de>, { - Ok(Identifier(Arc::new( - deserializer.deserialize_string(StringVisitor)?, - ))) + deserializer.deserialize_identifier(IdentifierVisitor) } } -struct StringVisitor; +struct IdentifierVisitor; -impl<'de> Visitor<'de> for StringVisitor { - type Value = String; +impl<'de> Visitor<'de> for IdentifierVisitor { + type Value = Identifier; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a UTF-8 string") } + + fn visit_char(self, v: char) -> Result + where + E: serde::de::Error, + { + self.visit_str(v.encode_utf8(&mut [0u8; 4])) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(Identifier::new(v)) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: serde::de::Error, + { + self.visit_str(v) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + self.visit_str(&v) + } } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index a6c29b5..046440e 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -272,11 +272,13 @@ impl InterpreterError { Some(error), ), DustError::Runtime { error, position } => { - let error_message = match &error { - RuntimeError::Io(_) => todo!(), + let note = match &error { + RuntimeError::Io(io_error) => &io_error.to_string(), RuntimeError::RwLockPoison(_) => todo!(), - RuntimeError::ValidationFailure(_) => todo!(), - RuntimeError::SerdeJson(serde_json_error) => serde_json_error.to_string(), + RuntimeError::ValidationFailure(_) => { + "This is the interpreter's fault. Please submit a bug with this error message." + } + RuntimeError::SerdeJson(serde_json_error) => &serde_json_error.to_string(), }; ( @@ -286,14 +288,12 @@ impl InterpreterError { position.1, ) .with_message("An error occured that forced the program to exit.") - .with_note( + .with_help( "There may be unexpected side-effects because the program could not finish.", ) - .with_help( - "This is the interpreter's fault. Please submit a bug with this error message.", - ) + .with_note(note) .with_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message(error_message) + Label::new((self.source_id.clone(), position.0..position.1)).with_message("Error occured here.") ), if let RuntimeError::ValidationFailure(validation_error) = error { diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 1139d40..15643f6 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -6,6 +6,7 @@ use std::{ sync::Arc, }; +use chumsky::container::Container; use serde::{ de::Visitor, ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple}, @@ -39,7 +40,7 @@ impl Value { Value(Arc::new(ValueInner::Integer(integer))) } - pub fn list(list: Vec>) -> Self { + pub fn list(list: Vec) -> Self { Value(Arc::new(ValueInner::List(list))) } @@ -85,7 +86,7 @@ impl Value { } } - pub fn as_list(&self) -> Option<&Vec>> { + pub fn as_list(&self) -> Option<&Vec> { if let ValueInner::List(list) = self.inner().as_ref() { Some(list) } else { @@ -113,9 +114,9 @@ impl Display for Value { for (index, value) in list.into_iter().enumerate() { if index == list.len() - 1 { - write!(f, "{}", value.node)?; + write!(f, "{}", value)?; } else { - write!(f, "{}, ", value.node)?; + write!(f, "{}, ", value)?; } } @@ -215,7 +216,7 @@ impl Serialize for Value { let mut list_ser = serializer.serialize_seq(Some(list.len()))?; for item in list { - list_ser.serialize_element(&item.node)?; + list_ser.serialize_element(&item)?; } list_ser.end() @@ -264,10 +265,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Err(serde::de::Error::invalid_type( - serde::de::Unexpected::Bool(v), - &self, - )) + Ok(Value::boolean(v)) } fn visit_i8(self, v: i8) -> Result @@ -298,7 +296,7 @@ impl<'de> Visitor<'de> for ValueVisitor { Ok(Value::integer(v)) } - fn visit_i128(self, v: i128) -> Result + fn visit_i128(self, _: i128) -> Result where E: serde::de::Error, { @@ -333,7 +331,7 @@ impl<'de> Visitor<'de> for ValueVisitor { Ok(Value::integer(v as i64)) } - fn visit_u128(self, v: u128) -> Result + fn visit_u128(self, _: u128) -> Result where E: serde::de::Error, { @@ -351,10 +349,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Err(serde::de::Error::invalid_type( - serde::de::Unexpected::Float(v), - &self, - )) + Ok(Value::float(v)) } fn visit_char(self, v: char) -> Result @@ -368,10 +363,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Err(serde::de::Error::invalid_type( - serde::de::Unexpected::Str(v), - &self, - )) + Ok(Value::string(v)) } fn visit_borrowed_str(self, v: &'de str) -> Result @@ -454,26 +446,30 @@ impl<'de> Visitor<'de> for ValueVisitor { )) } - fn visit_seq(self, seq: A) -> Result + fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, { - let _ = seq; - Err(serde::de::Error::invalid_type( - serde::de::Unexpected::Seq, - &self, - )) + let mut list = Vec::with_capacity(seq.size_hint().unwrap_or(10)); + + while let Some(element) = seq.next_element()? { + list.push(element); + } + + Ok(Value::list(list)) } - fn visit_map(self, map: A) -> Result + fn visit_map(self, mut map: A) -> Result where A: serde::de::MapAccess<'de>, { - let _ = map; - Err(serde::de::Error::invalid_type( - serde::de::Unexpected::Map, - &self, - )) + let mut btree = BTreeMap::with_capacity(map.size_hint().unwrap_or(10)); + + while let Some((key, value)) = map.next_entry()? { + btree.insert(key, value); + } + + Ok(Value::map(btree)) } fn visit_enum(self, data: A) -> Result @@ -503,7 +499,7 @@ pub enum ValueInner { Float(f64), Function(Function), Integer(i64), - List(Vec>), + List(Vec), Map(BTreeMap), Range(Range), String(String), @@ -520,7 +516,7 @@ impl ValueInner { ValueInner::Float(_) => Type::Float, ValueInner::Integer(_) => Type::Integer, ValueInner::List(values) => { - let item_type = values.first().unwrap().node.r#type(context)?; + let item_type = values.first().unwrap().r#type(context)?; Type::List { length: values.len(), diff --git a/dust-lang/tests/values.rs b/dust-lang/tests/values.rs index 60b91b9..114823c 100644 --- a/dust-lang/tests/values.rs +++ b/dust-lang/tests/values.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use dust_lang::{ - abstract_tree::{Type, WithPos}, + abstract_tree::Type, error::{DustError, TypeConflict, ValidationError}, identifier::Identifier, *, @@ -89,9 +89,9 @@ fn list() { assert_eq!( interpret("test", "[1, 2, 'foobar']"), Ok(Some(Value::list(vec![ - Value::integer(1).with_position((1, 2)), - Value::integer(2).with_position((4, 5)), - Value::string("foobar".to_string()).with_position((7, 15)), + Value::integer(1), + Value::integer(2), + Value::string("foobar".to_string()), ]))) ); } diff --git a/examples/assets/data.json b/examples/assets/data.json new file mode 100644 index 0000000..6b3f6ad --- /dev/null +++ b/examples/assets/data.json @@ -0,0 +1,6 @@ +[ + { "name": "Sammy", "type": "shark", "clams": 5 }, + { "name": "Bubbles", "type": "orca", "clams": 3 }, + { "name": "Splish", "type": "dolphin", "clams": 2 }, + { "name": "Splash", "type": "dolphin", "clams": 2 } +]